mirror of https://github.com/GNOME/gimp.git
Let the user choose between elliptical, square, and diamond shaped brushes
1999-02-02 Owen Taylor <otaylor@gtk.org> * app/blob.[ch] app/ink.c: Let the user choose between elliptical, square, and diamond shaped brushes for the ink tool.
This commit is contained in:
parent
672cfafb02
commit
02b111b8ce
|
@ -1,3 +1,9 @@
|
||||||
|
1999-02-02 Owen Taylor <otaylor@gtk.org>
|
||||||
|
|
||||||
|
* app/blob.[ch] app/ink.c: Let the user choose between
|
||||||
|
elliptical, square, and diamond shaped brushes for
|
||||||
|
the ink tool.
|
||||||
|
|
||||||
Tue Feb 2 22:25:57 GMT 1999 Adam D. Moss <adam@gimp.org>
|
Tue Feb 2 22:25:57 GMT 1999 Adam D. Moss <adam@gimp.org>
|
||||||
|
|
||||||
* app/fileops.c: GIMP now automagically saves
|
* app/fileops.c: GIMP now automagically saves
|
||||||
|
|
150
app/blob.c
150
app/blob.c
|
@ -53,8 +53,8 @@ static void
|
||||||
blob_fill (Blob *b, EdgeType *present)
|
blob_fill (Blob *b, EdgeType *present)
|
||||||
{
|
{
|
||||||
int start;
|
int start;
|
||||||
int y, x1, x2, y1, y2, i1, i2;
|
int x1, x2, i1, i2;
|
||||||
int i, j;
|
int i;
|
||||||
|
|
||||||
/* Mark empty lines at top and bottom as unused */
|
/* Mark empty lines at top and bottom as unused */
|
||||||
|
|
||||||
|
@ -205,8 +205,8 @@ blob_fill (Blob *b, EdgeType *present)
|
||||||
static void
|
static void
|
||||||
blob_make_convex (Blob *b, EdgeType *present)
|
blob_make_convex (Blob *b, EdgeType *present)
|
||||||
{
|
{
|
||||||
int y, x1, x2, y1, y2, i1, i2;
|
int x1, x2, y1, y2, i1, i2;
|
||||||
int i, j;
|
int i;
|
||||||
int start;
|
int start;
|
||||||
|
|
||||||
/* Walk through edges, deleting points that aren't on convex hull */
|
/* Walk through edges, deleting points that aren't on convex hull */
|
||||||
|
@ -301,9 +301,8 @@ Blob *
|
||||||
blob_convex_union (Blob *b1, Blob *b2)
|
blob_convex_union (Blob *b1, Blob *b2)
|
||||||
{
|
{
|
||||||
Blob *result;
|
Blob *result;
|
||||||
int y, x1, x2, y1, y2, i1, i2;
|
int y;
|
||||||
int i, j;
|
int i, j;
|
||||||
int start;
|
|
||||||
EdgeType *present;
|
EdgeType *present;
|
||||||
|
|
||||||
/* Create the storage for the result */
|
/* Create the storage for the result */
|
||||||
|
@ -454,11 +453,148 @@ blob_line (Blob *b, int x0, int y0, int x1, int y1)
|
||||||
|
|
||||||
#define ELLIPSE_SHIFT 2
|
#define ELLIPSE_SHIFT 2
|
||||||
#define TABLE_SHIFT 14
|
#define TABLE_SHIFT 14
|
||||||
#define TOTAL_SHIFT ELLIPSE_SHIFT + TABLE_SHIFT
|
#define TOTAL_SHIFT (ELLIPSE_SHIFT + TABLE_SHIFT)
|
||||||
|
|
||||||
static int trig_initialized = 0;
|
static int trig_initialized = 0;
|
||||||
static int trig_table[TABLE_SIZE];
|
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
|
/* Scan convert an ellipse specified by _offsets_ of major and
|
||||||
minor axes, and by center into a blob */
|
minor axes, and by center into a blob */
|
||||||
Blob *
|
Blob *
|
||||||
|
|
|
@ -25,9 +25,15 @@
|
||||||
#ifndef __BLOB_H__
|
#ifndef __BLOB_H__
|
||||||
#define __BLOB_H__
|
#define __BLOB_H__
|
||||||
|
|
||||||
|
typedef struct _BlobPoint BlobPoint;
|
||||||
typedef struct _BlobSpan BlobSpan;
|
typedef struct _BlobSpan BlobSpan;
|
||||||
typedef struct _Blob Blob;
|
typedef struct _Blob Blob;
|
||||||
|
|
||||||
|
struct _BlobPoint {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
|
||||||
struct _BlobSpan {
|
struct _BlobSpan {
|
||||||
int left;
|
int left;
|
||||||
int right;
|
int right;
|
||||||
|
@ -41,6 +47,9 @@ struct _Blob {
|
||||||
|
|
||||||
|
|
||||||
Blob *blob_convex_union (Blob *b1, Blob *b2);
|
Blob *blob_convex_union (Blob *b1, Blob *b2);
|
||||||
|
Blob *blob_polygon (BlobPoint *points, int npoints);
|
||||||
|
Blob *blob_square (double xc, double yc, double xp, double yp, double xq, double yq);
|
||||||
|
Blob *blob_diamond (double xc, double yc, double xp, double yp, double xq, double yq);
|
||||||
Blob *blob_ellipse (double xc, double yc, double xp, double yp, double xq, double yq);
|
Blob *blob_ellipse (double xc, double yc, double xp, double yp, double xq, double yq);
|
||||||
void blob_bounds(Blob *b, int *x, int *y, int *width, int *height);
|
void blob_bounds(Blob *b, int *x, int *y, int *width, int *height);
|
||||||
|
|
||||||
|
|
184
app/ink.c
184
app/ink.c
|
@ -43,6 +43,8 @@
|
||||||
|
|
||||||
/* the Ink structures */
|
/* the Ink structures */
|
||||||
|
|
||||||
|
typedef Blob *(*BlobFunc) (double, double, double, double, double, double);
|
||||||
|
|
||||||
typedef struct _InkTool InkTool;
|
typedef struct _InkTool InkTool;
|
||||||
struct _InkTool
|
struct _InkTool
|
||||||
{
|
{
|
||||||
|
@ -64,14 +66,19 @@ struct _InkOptions
|
||||||
double sensitivity;
|
double sensitivity;
|
||||||
double tilt_sensitivity;
|
double tilt_sensitivity;
|
||||||
double tilt_angle;
|
double tilt_angle;
|
||||||
|
BlobFunc function;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _BrushWidget BrushWidget;
|
typedef struct _BrushWidget BrushWidget;
|
||||||
struct _BrushWidget
|
struct _BrushWidget
|
||||||
{
|
{
|
||||||
|
GtkWidget *widget;
|
||||||
gboolean state;
|
gboolean state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Global variable to store brush widget */
|
||||||
|
static BrushWidget *brush_widget;
|
||||||
|
|
||||||
/* undo blocks variables */
|
/* undo blocks variables */
|
||||||
static TileManager * undo_tiles = NULL;
|
static TileManager * undo_tiles = NULL;
|
||||||
|
|
||||||
|
@ -107,6 +114,15 @@ static void ink_cleanup (void);
|
||||||
|
|
||||||
static void ink_scale_update (GtkAdjustment *adjustment,
|
static void ink_scale_update (GtkAdjustment *adjustment,
|
||||||
gdouble *value);
|
gdouble *value);
|
||||||
|
static void ink_type_update (GtkWidget *radio_button,
|
||||||
|
BlobFunc function);
|
||||||
|
static GdkPixmap *blob_pixmap (GdkColormap *colormap,
|
||||||
|
GdkVisual *visual,
|
||||||
|
BlobFunc function);
|
||||||
|
static void paint_blob (GdkDrawable *drawable,
|
||||||
|
GdkGC *gc,
|
||||||
|
Blob *blob);
|
||||||
|
|
||||||
/* Rendering functions */
|
/* Rendering functions */
|
||||||
|
|
||||||
static void ink_set_paint_area (InkTool *ink_tool,
|
static void ink_set_paint_area (InkTool *ink_tool,
|
||||||
|
@ -153,18 +169,22 @@ static InkOptions *
|
||||||
create_ink_options ()
|
create_ink_options ()
|
||||||
{
|
{
|
||||||
GtkWidget *vbox;
|
GtkWidget *vbox;
|
||||||
|
GtkWidget *util_vbox;
|
||||||
GtkWidget *hbox;
|
GtkWidget *hbox;
|
||||||
GtkWidget *label;
|
GtkWidget *label;
|
||||||
|
GtkWidget *radio_button;
|
||||||
|
GtkWidget *pixmap_widget;
|
||||||
GtkWidget *slider;
|
GtkWidget *slider;
|
||||||
GtkWidget *aspect_frame;
|
GtkWidget *aspect_frame;
|
||||||
GtkWidget *darea;
|
GtkWidget *darea;
|
||||||
GtkAdjustment *adj;
|
GtkAdjustment *adj;
|
||||||
|
|
||||||
BrushWidget *brush_widget;
|
GdkPixmap *pixmap;
|
||||||
|
|
||||||
InkOptions *options;
|
InkOptions *options;
|
||||||
|
|
||||||
/* the new options structure */
|
/* the new options structure */
|
||||||
options = (InkOptions *) g_malloc (sizeof (InkOptions));
|
options = g_new (InkOptions, 1);
|
||||||
|
|
||||||
options->size = 3.0;
|
options->size = 3.0;
|
||||||
options->sensitivity = 1.0;
|
options->sensitivity = 1.0;
|
||||||
|
@ -172,6 +192,7 @@ create_ink_options ()
|
||||||
options->angle = 0.0;
|
options->angle = 0.0;
|
||||||
options->tilt_sensitivity = 1.0;
|
options->tilt_sensitivity = 1.0;
|
||||||
options->tilt_angle = 0.0;
|
options->tilt_angle = 0.0;
|
||||||
|
options->function = blob_ellipse;
|
||||||
|
|
||||||
/* the main vbox */
|
/* the main vbox */
|
||||||
vbox = gtk_vbox_new (FALSE, 1);
|
vbox = gtk_vbox_new (FALSE, 1);
|
||||||
|
@ -245,21 +266,80 @@ create_ink_options ()
|
||||||
(GtkSignalFunc) ink_scale_update,
|
(GtkSignalFunc) ink_scale_update,
|
||||||
&options->tilt_angle);
|
&options->tilt_angle);
|
||||||
|
|
||||||
|
/* Brush type radiobuttons */
|
||||||
|
|
||||||
|
hbox = gtk_hbox_new (FALSE, 2);
|
||||||
|
gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
|
||||||
|
|
||||||
|
util_vbox = gtk_vbox_new (FALSE, 2);
|
||||||
|
gtk_box_pack_start (GTK_BOX(hbox), util_vbox, FALSE, FALSE, 5);
|
||||||
|
|
||||||
|
label = gtk_label_new (_("Type:"));
|
||||||
|
gtk_box_pack_start (GTK_BOX (util_vbox), label, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
pixmap = blob_pixmap (gtk_widget_get_colormap (util_vbox),
|
||||||
|
gtk_widget_get_visual (util_vbox),
|
||||||
|
blob_ellipse);
|
||||||
|
|
||||||
|
pixmap_widget = gtk_pixmap_new (pixmap, NULL);
|
||||||
|
gdk_pixmap_unref (pixmap);
|
||||||
|
|
||||||
|
radio_button = gtk_radio_button_new (NULL);
|
||||||
|
gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
|
||||||
|
GTK_SIGNAL_FUNC (ink_type_update),
|
||||||
|
(gpointer)blob_ellipse);
|
||||||
|
|
||||||
|
gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
|
||||||
|
gtk_box_pack_start (GTK_BOX (util_vbox), radio_button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
pixmap = blob_pixmap (gtk_widget_get_colormap (util_vbox),
|
||||||
|
gtk_widget_get_visual (util_vbox),
|
||||||
|
blob_square);
|
||||||
|
|
||||||
|
pixmap_widget = gtk_pixmap_new (pixmap, NULL);
|
||||||
|
gdk_pixmap_unref (pixmap);
|
||||||
|
|
||||||
|
radio_button = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio_button));
|
||||||
|
gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
|
||||||
|
GTK_SIGNAL_FUNC (ink_type_update),
|
||||||
|
(gpointer)blob_square);
|
||||||
|
|
||||||
|
gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
|
||||||
|
gtk_box_pack_start (GTK_BOX (util_vbox), radio_button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
pixmap = blob_pixmap (gtk_widget_get_colormap (util_vbox),
|
||||||
|
gtk_widget_get_visual (util_vbox),
|
||||||
|
blob_diamond);
|
||||||
|
|
||||||
|
pixmap_widget = gtk_pixmap_new (pixmap, NULL);
|
||||||
|
gdk_pixmap_unref (pixmap);
|
||||||
|
|
||||||
|
radio_button = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio_button));
|
||||||
|
gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
|
||||||
|
GTK_SIGNAL_FUNC (ink_type_update),
|
||||||
|
(gpointer)blob_diamond);
|
||||||
|
|
||||||
|
gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
|
||||||
|
gtk_box_pack_start (GTK_BOX (util_vbox), radio_button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
/* Brush shape widget */
|
/* Brush shape widget */
|
||||||
|
|
||||||
brush_widget = g_new (BrushWidget, 1);
|
brush_widget = g_new (BrushWidget, 1);
|
||||||
brush_widget->state = FALSE;
|
brush_widget->state = FALSE;
|
||||||
|
|
||||||
hbox = gtk_hbox_new (FALSE, 2);
|
util_vbox = gtk_vbox_new (FALSE, 2);
|
||||||
gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
|
gtk_box_pack_start (GTK_BOX(hbox), util_vbox, FALSE, FALSE, 5);
|
||||||
|
|
||||||
label = gtk_label_new (_("Shape:"));
|
label = gtk_label_new (_("Shape:"));
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
gtk_box_pack_start (GTK_BOX (util_vbox), label, FALSE, FALSE, 0);
|
||||||
|
|
||||||
aspect_frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1.0, FALSE);
|
aspect_frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1.0, FALSE);
|
||||||
gtk_frame_set_shadow_type (GTK_FRAME(aspect_frame), GTK_SHADOW_IN);
|
gtk_frame_set_shadow_type (GTK_FRAME(aspect_frame), GTK_SHADOW_IN);
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), aspect_frame, TRUE, TRUE, 2);
|
gtk_box_pack_start (GTK_BOX (util_vbox), aspect_frame, TRUE, TRUE, 2);
|
||||||
|
|
||||||
darea = gtk_drawing_area_new();
|
darea = gtk_drawing_area_new();
|
||||||
|
brush_widget->widget = darea;
|
||||||
|
|
||||||
gtk_drawing_area_size (GTK_DRAWING_AREA(darea), 60, 60);
|
gtk_drawing_area_size (GTK_DRAWING_AREA(darea), 60, 60);
|
||||||
gtk_container_add (GTK_CONTAINER(aspect_frame), darea);
|
gtk_container_add (GTK_CONTAINER(aspect_frame), darea);
|
||||||
|
|
||||||
|
@ -320,24 +400,15 @@ static void
|
||||||
brush_widget_draw_brush (BrushWidget *brush_widget, GtkWidget *w,
|
brush_widget_draw_brush (BrushWidget *brush_widget, GtkWidget *w,
|
||||||
double xc, double yc, double radius)
|
double xc, double yc, double radius)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
Blob *b;
|
Blob *b;
|
||||||
|
|
||||||
b = blob_ellipse(xc,yc,
|
b = ink_options->function (xc,yc,
|
||||||
radius*cos(ink_options->angle),
|
radius*cos(ink_options->angle),
|
||||||
radius*sin(ink_options->angle),
|
radius*sin(ink_options->angle),
|
||||||
-(radius/ink_options->aspect)*sin(ink_options->angle),
|
-(radius/ink_options->aspect)*sin(ink_options->angle),
|
||||||
(radius/ink_options->aspect)*cos(ink_options->angle));
|
(radius/ink_options->aspect)*cos(ink_options->angle));
|
||||||
|
|
||||||
for (i=0;i<b->height;i++)
|
paint_blob (w->window, w->style->fg_gc[w->state],b);
|
||||||
{
|
|
||||||
if (b->data[i].left <= b->data[i].right)
|
|
||||||
gdk_draw_line (w->window,
|
|
||||||
w->style->fg_gc[w->state],
|
|
||||||
b->data[i].left,i+b->y,
|
|
||||||
b->data[i].right+1,i+b->y);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free (b);
|
g_free (b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,6 +502,69 @@ ink_scale_update (GtkAdjustment *adjustment, gdouble *value)
|
||||||
*value = adjustment->value;
|
*value = adjustment->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ink_type_update (GtkWidget *radio_button,
|
||||||
|
BlobFunc function)
|
||||||
|
{
|
||||||
|
if (GTK_TOGGLE_BUTTON (radio_button)->active)
|
||||||
|
ink_options->function = function;
|
||||||
|
|
||||||
|
gtk_widget_queue_draw (brush_widget->widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return a black-on white pixmap in the given colormap and
|
||||||
|
* visual that represents the BlobFunc 'function'
|
||||||
|
*/
|
||||||
|
static GdkPixmap *
|
||||||
|
blob_pixmap (GdkColormap *colormap,
|
||||||
|
GdkVisual *visual,
|
||||||
|
BlobFunc function)
|
||||||
|
{
|
||||||
|
GdkPixmap *pixmap;
|
||||||
|
GdkGC *black_gc, *white_gc;
|
||||||
|
GdkColor tmp_color;
|
||||||
|
Blob *blob;
|
||||||
|
|
||||||
|
pixmap = gdk_pixmap_new (NULL, 22, 21, visual->depth);
|
||||||
|
|
||||||
|
black_gc = gdk_gc_new (pixmap);
|
||||||
|
gdk_color_black (colormap, &tmp_color);
|
||||||
|
gdk_gc_set_foreground (black_gc, &tmp_color);
|
||||||
|
|
||||||
|
white_gc = gdk_gc_new (pixmap);
|
||||||
|
gdk_color_white (colormap, &tmp_color);
|
||||||
|
gdk_gc_set_foreground (white_gc, &tmp_color);
|
||||||
|
|
||||||
|
gdk_draw_rectangle (pixmap, white_gc, TRUE, 0, 0, 21, 20);
|
||||||
|
gdk_draw_rectangle (pixmap, black_gc, FALSE, 0, 0, 21, 20);
|
||||||
|
blob = (*function) (10, 10, 8, 0, 0, 8);
|
||||||
|
paint_blob (pixmap, black_gc, blob);
|
||||||
|
|
||||||
|
gdk_gc_unref (white_gc);
|
||||||
|
gdk_gc_unref (black_gc);
|
||||||
|
|
||||||
|
return pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draw a blob onto a drawable with the specified graphics context
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
paint_blob (GdkDrawable *drawable, GdkGC *gc,
|
||||||
|
Blob *blob)
|
||||||
|
{
|
||||||
|
int 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static Blob *
|
static Blob *
|
||||||
ink_pen_ellipse (gdouble x_center, gdouble y_center,
|
ink_pen_ellipse (gdouble x_center, gdouble y_center,
|
||||||
gdouble pressure, gdouble xtilt, gdouble ytilt)
|
gdouble pressure, gdouble xtilt, gdouble ytilt)
|
||||||
|
@ -484,9 +618,9 @@ ink_pen_ellipse (gdouble x_center, gdouble y_center,
|
||||||
radmin = SUBSAMPLE * size/aspect;
|
radmin = SUBSAMPLE * size/aspect;
|
||||||
if (radmin < 1.0) radmin = 1.0;
|
if (radmin < 1.0) radmin = 1.0;
|
||||||
|
|
||||||
return blob_ellipse(x_center * SUBSAMPLE, y_center * SUBSAMPLE,
|
return ink_options->function (x_center * SUBSAMPLE, y_center * SUBSAMPLE,
|
||||||
radmin*aspect*tcos, radmin*aspect*tsin,
|
radmin*aspect*tcos, radmin*aspect*tsin,
|
||||||
-radmin*tsin, radmin*tcos);
|
-radmin*tsin, radmin*tcos);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -53,8 +53,8 @@ static void
|
||||||
blob_fill (Blob *b, EdgeType *present)
|
blob_fill (Blob *b, EdgeType *present)
|
||||||
{
|
{
|
||||||
int start;
|
int start;
|
||||||
int y, x1, x2, y1, y2, i1, i2;
|
int x1, x2, i1, i2;
|
||||||
int i, j;
|
int i;
|
||||||
|
|
||||||
/* Mark empty lines at top and bottom as unused */
|
/* Mark empty lines at top and bottom as unused */
|
||||||
|
|
||||||
|
@ -205,8 +205,8 @@ blob_fill (Blob *b, EdgeType *present)
|
||||||
static void
|
static void
|
||||||
blob_make_convex (Blob *b, EdgeType *present)
|
blob_make_convex (Blob *b, EdgeType *present)
|
||||||
{
|
{
|
||||||
int y, x1, x2, y1, y2, i1, i2;
|
int x1, x2, y1, y2, i1, i2;
|
||||||
int i, j;
|
int i;
|
||||||
int start;
|
int start;
|
||||||
|
|
||||||
/* Walk through edges, deleting points that aren't on convex hull */
|
/* Walk through edges, deleting points that aren't on convex hull */
|
||||||
|
@ -301,9 +301,8 @@ Blob *
|
||||||
blob_convex_union (Blob *b1, Blob *b2)
|
blob_convex_union (Blob *b1, Blob *b2)
|
||||||
{
|
{
|
||||||
Blob *result;
|
Blob *result;
|
||||||
int y, x1, x2, y1, y2, i1, i2;
|
int y;
|
||||||
int i, j;
|
int i, j;
|
||||||
int start;
|
|
||||||
EdgeType *present;
|
EdgeType *present;
|
||||||
|
|
||||||
/* Create the storage for the result */
|
/* Create the storage for the result */
|
||||||
|
@ -454,11 +453,148 @@ blob_line (Blob *b, int x0, int y0, int x1, int y1)
|
||||||
|
|
||||||
#define ELLIPSE_SHIFT 2
|
#define ELLIPSE_SHIFT 2
|
||||||
#define TABLE_SHIFT 14
|
#define TABLE_SHIFT 14
|
||||||
#define TOTAL_SHIFT ELLIPSE_SHIFT + TABLE_SHIFT
|
#define TOTAL_SHIFT (ELLIPSE_SHIFT + TABLE_SHIFT)
|
||||||
|
|
||||||
static int trig_initialized = 0;
|
static int trig_initialized = 0;
|
||||||
static int trig_table[TABLE_SIZE];
|
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
|
/* Scan convert an ellipse specified by _offsets_ of major and
|
||||||
minor axes, and by center into a blob */
|
minor axes, and by center into a blob */
|
||||||
Blob *
|
Blob *
|
||||||
|
|
|
@ -25,9 +25,15 @@
|
||||||
#ifndef __BLOB_H__
|
#ifndef __BLOB_H__
|
||||||
#define __BLOB_H__
|
#define __BLOB_H__
|
||||||
|
|
||||||
|
typedef struct _BlobPoint BlobPoint;
|
||||||
typedef struct _BlobSpan BlobSpan;
|
typedef struct _BlobSpan BlobSpan;
|
||||||
typedef struct _Blob Blob;
|
typedef struct _Blob Blob;
|
||||||
|
|
||||||
|
struct _BlobPoint {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
|
||||||
struct _BlobSpan {
|
struct _BlobSpan {
|
||||||
int left;
|
int left;
|
||||||
int right;
|
int right;
|
||||||
|
@ -41,6 +47,9 @@ struct _Blob {
|
||||||
|
|
||||||
|
|
||||||
Blob *blob_convex_union (Blob *b1, Blob *b2);
|
Blob *blob_convex_union (Blob *b1, Blob *b2);
|
||||||
|
Blob *blob_polygon (BlobPoint *points, int npoints);
|
||||||
|
Blob *blob_square (double xc, double yc, double xp, double yp, double xq, double yq);
|
||||||
|
Blob *blob_diamond (double xc, double yc, double xp, double yp, double xq, double yq);
|
||||||
Blob *blob_ellipse (double xc, double yc, double xp, double yp, double xq, double yq);
|
Blob *blob_ellipse (double xc, double yc, double xp, double yp, double xq, double yq);
|
||||||
void blob_bounds(Blob *b, int *x, int *y, int *width, int *height);
|
void blob_bounds(Blob *b, int *x, int *y, int *width, int *height);
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,8 @@
|
||||||
|
|
||||||
/* the Ink structures */
|
/* the Ink structures */
|
||||||
|
|
||||||
|
typedef Blob *(*BlobFunc) (double, double, double, double, double, double);
|
||||||
|
|
||||||
typedef struct _InkTool InkTool;
|
typedef struct _InkTool InkTool;
|
||||||
struct _InkTool
|
struct _InkTool
|
||||||
{
|
{
|
||||||
|
@ -64,14 +66,19 @@ struct _InkOptions
|
||||||
double sensitivity;
|
double sensitivity;
|
||||||
double tilt_sensitivity;
|
double tilt_sensitivity;
|
||||||
double tilt_angle;
|
double tilt_angle;
|
||||||
|
BlobFunc function;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _BrushWidget BrushWidget;
|
typedef struct _BrushWidget BrushWidget;
|
||||||
struct _BrushWidget
|
struct _BrushWidget
|
||||||
{
|
{
|
||||||
|
GtkWidget *widget;
|
||||||
gboolean state;
|
gboolean state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Global variable to store brush widget */
|
||||||
|
static BrushWidget *brush_widget;
|
||||||
|
|
||||||
/* undo blocks variables */
|
/* undo blocks variables */
|
||||||
static TileManager * undo_tiles = NULL;
|
static TileManager * undo_tiles = NULL;
|
||||||
|
|
||||||
|
@ -107,6 +114,15 @@ static void ink_cleanup (void);
|
||||||
|
|
||||||
static void ink_scale_update (GtkAdjustment *adjustment,
|
static void ink_scale_update (GtkAdjustment *adjustment,
|
||||||
gdouble *value);
|
gdouble *value);
|
||||||
|
static void ink_type_update (GtkWidget *radio_button,
|
||||||
|
BlobFunc function);
|
||||||
|
static GdkPixmap *blob_pixmap (GdkColormap *colormap,
|
||||||
|
GdkVisual *visual,
|
||||||
|
BlobFunc function);
|
||||||
|
static void paint_blob (GdkDrawable *drawable,
|
||||||
|
GdkGC *gc,
|
||||||
|
Blob *blob);
|
||||||
|
|
||||||
/* Rendering functions */
|
/* Rendering functions */
|
||||||
|
|
||||||
static void ink_set_paint_area (InkTool *ink_tool,
|
static void ink_set_paint_area (InkTool *ink_tool,
|
||||||
|
@ -153,18 +169,22 @@ static InkOptions *
|
||||||
create_ink_options ()
|
create_ink_options ()
|
||||||
{
|
{
|
||||||
GtkWidget *vbox;
|
GtkWidget *vbox;
|
||||||
|
GtkWidget *util_vbox;
|
||||||
GtkWidget *hbox;
|
GtkWidget *hbox;
|
||||||
GtkWidget *label;
|
GtkWidget *label;
|
||||||
|
GtkWidget *radio_button;
|
||||||
|
GtkWidget *pixmap_widget;
|
||||||
GtkWidget *slider;
|
GtkWidget *slider;
|
||||||
GtkWidget *aspect_frame;
|
GtkWidget *aspect_frame;
|
||||||
GtkWidget *darea;
|
GtkWidget *darea;
|
||||||
GtkAdjustment *adj;
|
GtkAdjustment *adj;
|
||||||
|
|
||||||
BrushWidget *brush_widget;
|
GdkPixmap *pixmap;
|
||||||
|
|
||||||
InkOptions *options;
|
InkOptions *options;
|
||||||
|
|
||||||
/* the new options structure */
|
/* the new options structure */
|
||||||
options = (InkOptions *) g_malloc (sizeof (InkOptions));
|
options = g_new (InkOptions, 1);
|
||||||
|
|
||||||
options->size = 3.0;
|
options->size = 3.0;
|
||||||
options->sensitivity = 1.0;
|
options->sensitivity = 1.0;
|
||||||
|
@ -172,6 +192,7 @@ create_ink_options ()
|
||||||
options->angle = 0.0;
|
options->angle = 0.0;
|
||||||
options->tilt_sensitivity = 1.0;
|
options->tilt_sensitivity = 1.0;
|
||||||
options->tilt_angle = 0.0;
|
options->tilt_angle = 0.0;
|
||||||
|
options->function = blob_ellipse;
|
||||||
|
|
||||||
/* the main vbox */
|
/* the main vbox */
|
||||||
vbox = gtk_vbox_new (FALSE, 1);
|
vbox = gtk_vbox_new (FALSE, 1);
|
||||||
|
@ -245,21 +266,80 @@ create_ink_options ()
|
||||||
(GtkSignalFunc) ink_scale_update,
|
(GtkSignalFunc) ink_scale_update,
|
||||||
&options->tilt_angle);
|
&options->tilt_angle);
|
||||||
|
|
||||||
|
/* Brush type radiobuttons */
|
||||||
|
|
||||||
|
hbox = gtk_hbox_new (FALSE, 2);
|
||||||
|
gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
|
||||||
|
|
||||||
|
util_vbox = gtk_vbox_new (FALSE, 2);
|
||||||
|
gtk_box_pack_start (GTK_BOX(hbox), util_vbox, FALSE, FALSE, 5);
|
||||||
|
|
||||||
|
label = gtk_label_new (_("Type:"));
|
||||||
|
gtk_box_pack_start (GTK_BOX (util_vbox), label, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
pixmap = blob_pixmap (gtk_widget_get_colormap (util_vbox),
|
||||||
|
gtk_widget_get_visual (util_vbox),
|
||||||
|
blob_ellipse);
|
||||||
|
|
||||||
|
pixmap_widget = gtk_pixmap_new (pixmap, NULL);
|
||||||
|
gdk_pixmap_unref (pixmap);
|
||||||
|
|
||||||
|
radio_button = gtk_radio_button_new (NULL);
|
||||||
|
gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
|
||||||
|
GTK_SIGNAL_FUNC (ink_type_update),
|
||||||
|
(gpointer)blob_ellipse);
|
||||||
|
|
||||||
|
gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
|
||||||
|
gtk_box_pack_start (GTK_BOX (util_vbox), radio_button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
pixmap = blob_pixmap (gtk_widget_get_colormap (util_vbox),
|
||||||
|
gtk_widget_get_visual (util_vbox),
|
||||||
|
blob_square);
|
||||||
|
|
||||||
|
pixmap_widget = gtk_pixmap_new (pixmap, NULL);
|
||||||
|
gdk_pixmap_unref (pixmap);
|
||||||
|
|
||||||
|
radio_button = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio_button));
|
||||||
|
gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
|
||||||
|
GTK_SIGNAL_FUNC (ink_type_update),
|
||||||
|
(gpointer)blob_square);
|
||||||
|
|
||||||
|
gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
|
||||||
|
gtk_box_pack_start (GTK_BOX (util_vbox), radio_button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
pixmap = blob_pixmap (gtk_widget_get_colormap (util_vbox),
|
||||||
|
gtk_widget_get_visual (util_vbox),
|
||||||
|
blob_diamond);
|
||||||
|
|
||||||
|
pixmap_widget = gtk_pixmap_new (pixmap, NULL);
|
||||||
|
gdk_pixmap_unref (pixmap);
|
||||||
|
|
||||||
|
radio_button = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio_button));
|
||||||
|
gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
|
||||||
|
GTK_SIGNAL_FUNC (ink_type_update),
|
||||||
|
(gpointer)blob_diamond);
|
||||||
|
|
||||||
|
gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
|
||||||
|
gtk_box_pack_start (GTK_BOX (util_vbox), radio_button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
/* Brush shape widget */
|
/* Brush shape widget */
|
||||||
|
|
||||||
brush_widget = g_new (BrushWidget, 1);
|
brush_widget = g_new (BrushWidget, 1);
|
||||||
brush_widget->state = FALSE;
|
brush_widget->state = FALSE;
|
||||||
|
|
||||||
hbox = gtk_hbox_new (FALSE, 2);
|
util_vbox = gtk_vbox_new (FALSE, 2);
|
||||||
gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
|
gtk_box_pack_start (GTK_BOX(hbox), util_vbox, FALSE, FALSE, 5);
|
||||||
|
|
||||||
label = gtk_label_new (_("Shape:"));
|
label = gtk_label_new (_("Shape:"));
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
gtk_box_pack_start (GTK_BOX (util_vbox), label, FALSE, FALSE, 0);
|
||||||
|
|
||||||
aspect_frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1.0, FALSE);
|
aspect_frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1.0, FALSE);
|
||||||
gtk_frame_set_shadow_type (GTK_FRAME(aspect_frame), GTK_SHADOW_IN);
|
gtk_frame_set_shadow_type (GTK_FRAME(aspect_frame), GTK_SHADOW_IN);
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), aspect_frame, TRUE, TRUE, 2);
|
gtk_box_pack_start (GTK_BOX (util_vbox), aspect_frame, TRUE, TRUE, 2);
|
||||||
|
|
||||||
darea = gtk_drawing_area_new();
|
darea = gtk_drawing_area_new();
|
||||||
|
brush_widget->widget = darea;
|
||||||
|
|
||||||
gtk_drawing_area_size (GTK_DRAWING_AREA(darea), 60, 60);
|
gtk_drawing_area_size (GTK_DRAWING_AREA(darea), 60, 60);
|
||||||
gtk_container_add (GTK_CONTAINER(aspect_frame), darea);
|
gtk_container_add (GTK_CONTAINER(aspect_frame), darea);
|
||||||
|
|
||||||
|
@ -320,24 +400,15 @@ static void
|
||||||
brush_widget_draw_brush (BrushWidget *brush_widget, GtkWidget *w,
|
brush_widget_draw_brush (BrushWidget *brush_widget, GtkWidget *w,
|
||||||
double xc, double yc, double radius)
|
double xc, double yc, double radius)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
Blob *b;
|
Blob *b;
|
||||||
|
|
||||||
b = blob_ellipse(xc,yc,
|
b = ink_options->function (xc,yc,
|
||||||
radius*cos(ink_options->angle),
|
radius*cos(ink_options->angle),
|
||||||
radius*sin(ink_options->angle),
|
radius*sin(ink_options->angle),
|
||||||
-(radius/ink_options->aspect)*sin(ink_options->angle),
|
-(radius/ink_options->aspect)*sin(ink_options->angle),
|
||||||
(radius/ink_options->aspect)*cos(ink_options->angle));
|
(radius/ink_options->aspect)*cos(ink_options->angle));
|
||||||
|
|
||||||
for (i=0;i<b->height;i++)
|
paint_blob (w->window, w->style->fg_gc[w->state],b);
|
||||||
{
|
|
||||||
if (b->data[i].left <= b->data[i].right)
|
|
||||||
gdk_draw_line (w->window,
|
|
||||||
w->style->fg_gc[w->state],
|
|
||||||
b->data[i].left,i+b->y,
|
|
||||||
b->data[i].right+1,i+b->y);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free (b);
|
g_free (b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,6 +502,69 @@ ink_scale_update (GtkAdjustment *adjustment, gdouble *value)
|
||||||
*value = adjustment->value;
|
*value = adjustment->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ink_type_update (GtkWidget *radio_button,
|
||||||
|
BlobFunc function)
|
||||||
|
{
|
||||||
|
if (GTK_TOGGLE_BUTTON (radio_button)->active)
|
||||||
|
ink_options->function = function;
|
||||||
|
|
||||||
|
gtk_widget_queue_draw (brush_widget->widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return a black-on white pixmap in the given colormap and
|
||||||
|
* visual that represents the BlobFunc 'function'
|
||||||
|
*/
|
||||||
|
static GdkPixmap *
|
||||||
|
blob_pixmap (GdkColormap *colormap,
|
||||||
|
GdkVisual *visual,
|
||||||
|
BlobFunc function)
|
||||||
|
{
|
||||||
|
GdkPixmap *pixmap;
|
||||||
|
GdkGC *black_gc, *white_gc;
|
||||||
|
GdkColor tmp_color;
|
||||||
|
Blob *blob;
|
||||||
|
|
||||||
|
pixmap = gdk_pixmap_new (NULL, 22, 21, visual->depth);
|
||||||
|
|
||||||
|
black_gc = gdk_gc_new (pixmap);
|
||||||
|
gdk_color_black (colormap, &tmp_color);
|
||||||
|
gdk_gc_set_foreground (black_gc, &tmp_color);
|
||||||
|
|
||||||
|
white_gc = gdk_gc_new (pixmap);
|
||||||
|
gdk_color_white (colormap, &tmp_color);
|
||||||
|
gdk_gc_set_foreground (white_gc, &tmp_color);
|
||||||
|
|
||||||
|
gdk_draw_rectangle (pixmap, white_gc, TRUE, 0, 0, 21, 20);
|
||||||
|
gdk_draw_rectangle (pixmap, black_gc, FALSE, 0, 0, 21, 20);
|
||||||
|
blob = (*function) (10, 10, 8, 0, 0, 8);
|
||||||
|
paint_blob (pixmap, black_gc, blob);
|
||||||
|
|
||||||
|
gdk_gc_unref (white_gc);
|
||||||
|
gdk_gc_unref (black_gc);
|
||||||
|
|
||||||
|
return pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draw a blob onto a drawable with the specified graphics context
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
paint_blob (GdkDrawable *drawable, GdkGC *gc,
|
||||||
|
Blob *blob)
|
||||||
|
{
|
||||||
|
int 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static Blob *
|
static Blob *
|
||||||
ink_pen_ellipse (gdouble x_center, gdouble y_center,
|
ink_pen_ellipse (gdouble x_center, gdouble y_center,
|
||||||
gdouble pressure, gdouble xtilt, gdouble ytilt)
|
gdouble pressure, gdouble xtilt, gdouble ytilt)
|
||||||
|
@ -484,9 +618,9 @@ ink_pen_ellipse (gdouble x_center, gdouble y_center,
|
||||||
radmin = SUBSAMPLE * size/aspect;
|
radmin = SUBSAMPLE * size/aspect;
|
||||||
if (radmin < 1.0) radmin = 1.0;
|
if (radmin < 1.0) radmin = 1.0;
|
||||||
|
|
||||||
return blob_ellipse(x_center * SUBSAMPLE, y_center * SUBSAMPLE,
|
return ink_options->function (x_center * SUBSAMPLE, y_center * SUBSAMPLE,
|
||||||
radmin*aspect*tcos, radmin*aspect*tsin,
|
radmin*aspect*tcos, radmin*aspect*tsin,
|
||||||
-radmin*tsin, radmin*tcos);
|
-radmin*tsin, radmin*tcos);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
150
app/tools/blob.c
150
app/tools/blob.c
|
@ -53,8 +53,8 @@ static void
|
||||||
blob_fill (Blob *b, EdgeType *present)
|
blob_fill (Blob *b, EdgeType *present)
|
||||||
{
|
{
|
||||||
int start;
|
int start;
|
||||||
int y, x1, x2, y1, y2, i1, i2;
|
int x1, x2, i1, i2;
|
||||||
int i, j;
|
int i;
|
||||||
|
|
||||||
/* Mark empty lines at top and bottom as unused */
|
/* Mark empty lines at top and bottom as unused */
|
||||||
|
|
||||||
|
@ -205,8 +205,8 @@ blob_fill (Blob *b, EdgeType *present)
|
||||||
static void
|
static void
|
||||||
blob_make_convex (Blob *b, EdgeType *present)
|
blob_make_convex (Blob *b, EdgeType *present)
|
||||||
{
|
{
|
||||||
int y, x1, x2, y1, y2, i1, i2;
|
int x1, x2, y1, y2, i1, i2;
|
||||||
int i, j;
|
int i;
|
||||||
int start;
|
int start;
|
||||||
|
|
||||||
/* Walk through edges, deleting points that aren't on convex hull */
|
/* Walk through edges, deleting points that aren't on convex hull */
|
||||||
|
@ -301,9 +301,8 @@ Blob *
|
||||||
blob_convex_union (Blob *b1, Blob *b2)
|
blob_convex_union (Blob *b1, Blob *b2)
|
||||||
{
|
{
|
||||||
Blob *result;
|
Blob *result;
|
||||||
int y, x1, x2, y1, y2, i1, i2;
|
int y;
|
||||||
int i, j;
|
int i, j;
|
||||||
int start;
|
|
||||||
EdgeType *present;
|
EdgeType *present;
|
||||||
|
|
||||||
/* Create the storage for the result */
|
/* Create the storage for the result */
|
||||||
|
@ -454,11 +453,148 @@ blob_line (Blob *b, int x0, int y0, int x1, int y1)
|
||||||
|
|
||||||
#define ELLIPSE_SHIFT 2
|
#define ELLIPSE_SHIFT 2
|
||||||
#define TABLE_SHIFT 14
|
#define TABLE_SHIFT 14
|
||||||
#define TOTAL_SHIFT ELLIPSE_SHIFT + TABLE_SHIFT
|
#define TOTAL_SHIFT (ELLIPSE_SHIFT + TABLE_SHIFT)
|
||||||
|
|
||||||
static int trig_initialized = 0;
|
static int trig_initialized = 0;
|
||||||
static int trig_table[TABLE_SIZE];
|
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
|
/* Scan convert an ellipse specified by _offsets_ of major and
|
||||||
minor axes, and by center into a blob */
|
minor axes, and by center into a blob */
|
||||||
Blob *
|
Blob *
|
||||||
|
|
|
@ -25,9 +25,15 @@
|
||||||
#ifndef __BLOB_H__
|
#ifndef __BLOB_H__
|
||||||
#define __BLOB_H__
|
#define __BLOB_H__
|
||||||
|
|
||||||
|
typedef struct _BlobPoint BlobPoint;
|
||||||
typedef struct _BlobSpan BlobSpan;
|
typedef struct _BlobSpan BlobSpan;
|
||||||
typedef struct _Blob Blob;
|
typedef struct _Blob Blob;
|
||||||
|
|
||||||
|
struct _BlobPoint {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
|
||||||
struct _BlobSpan {
|
struct _BlobSpan {
|
||||||
int left;
|
int left;
|
||||||
int right;
|
int right;
|
||||||
|
@ -41,6 +47,9 @@ struct _Blob {
|
||||||
|
|
||||||
|
|
||||||
Blob *blob_convex_union (Blob *b1, Blob *b2);
|
Blob *blob_convex_union (Blob *b1, Blob *b2);
|
||||||
|
Blob *blob_polygon (BlobPoint *points, int npoints);
|
||||||
|
Blob *blob_square (double xc, double yc, double xp, double yp, double xq, double yq);
|
||||||
|
Blob *blob_diamond (double xc, double yc, double xp, double yp, double xq, double yq);
|
||||||
Blob *blob_ellipse (double xc, double yc, double xp, double yp, double xq, double yq);
|
Blob *blob_ellipse (double xc, double yc, double xp, double yp, double xq, double yq);
|
||||||
void blob_bounds(Blob *b, int *x, int *y, int *width, int *height);
|
void blob_bounds(Blob *b, int *x, int *y, int *width, int *height);
|
||||||
|
|
||||||
|
|
|
@ -53,8 +53,8 @@ static void
|
||||||
blob_fill (Blob *b, EdgeType *present)
|
blob_fill (Blob *b, EdgeType *present)
|
||||||
{
|
{
|
||||||
int start;
|
int start;
|
||||||
int y, x1, x2, y1, y2, i1, i2;
|
int x1, x2, i1, i2;
|
||||||
int i, j;
|
int i;
|
||||||
|
|
||||||
/* Mark empty lines at top and bottom as unused */
|
/* Mark empty lines at top and bottom as unused */
|
||||||
|
|
||||||
|
@ -205,8 +205,8 @@ blob_fill (Blob *b, EdgeType *present)
|
||||||
static void
|
static void
|
||||||
blob_make_convex (Blob *b, EdgeType *present)
|
blob_make_convex (Blob *b, EdgeType *present)
|
||||||
{
|
{
|
||||||
int y, x1, x2, y1, y2, i1, i2;
|
int x1, x2, y1, y2, i1, i2;
|
||||||
int i, j;
|
int i;
|
||||||
int start;
|
int start;
|
||||||
|
|
||||||
/* Walk through edges, deleting points that aren't on convex hull */
|
/* Walk through edges, deleting points that aren't on convex hull */
|
||||||
|
@ -301,9 +301,8 @@ Blob *
|
||||||
blob_convex_union (Blob *b1, Blob *b2)
|
blob_convex_union (Blob *b1, Blob *b2)
|
||||||
{
|
{
|
||||||
Blob *result;
|
Blob *result;
|
||||||
int y, x1, x2, y1, y2, i1, i2;
|
int y;
|
||||||
int i, j;
|
int i, j;
|
||||||
int start;
|
|
||||||
EdgeType *present;
|
EdgeType *present;
|
||||||
|
|
||||||
/* Create the storage for the result */
|
/* Create the storage for the result */
|
||||||
|
@ -454,11 +453,148 @@ blob_line (Blob *b, int x0, int y0, int x1, int y1)
|
||||||
|
|
||||||
#define ELLIPSE_SHIFT 2
|
#define ELLIPSE_SHIFT 2
|
||||||
#define TABLE_SHIFT 14
|
#define TABLE_SHIFT 14
|
||||||
#define TOTAL_SHIFT ELLIPSE_SHIFT + TABLE_SHIFT
|
#define TOTAL_SHIFT (ELLIPSE_SHIFT + TABLE_SHIFT)
|
||||||
|
|
||||||
static int trig_initialized = 0;
|
static int trig_initialized = 0;
|
||||||
static int trig_table[TABLE_SIZE];
|
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
|
/* Scan convert an ellipse specified by _offsets_ of major and
|
||||||
minor axes, and by center into a blob */
|
minor axes, and by center into a blob */
|
||||||
Blob *
|
Blob *
|
||||||
|
|
|
@ -25,9 +25,15 @@
|
||||||
#ifndef __BLOB_H__
|
#ifndef __BLOB_H__
|
||||||
#define __BLOB_H__
|
#define __BLOB_H__
|
||||||
|
|
||||||
|
typedef struct _BlobPoint BlobPoint;
|
||||||
typedef struct _BlobSpan BlobSpan;
|
typedef struct _BlobSpan BlobSpan;
|
||||||
typedef struct _Blob Blob;
|
typedef struct _Blob Blob;
|
||||||
|
|
||||||
|
struct _BlobPoint {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
|
||||||
struct _BlobSpan {
|
struct _BlobSpan {
|
||||||
int left;
|
int left;
|
||||||
int right;
|
int right;
|
||||||
|
@ -41,6 +47,9 @@ struct _Blob {
|
||||||
|
|
||||||
|
|
||||||
Blob *blob_convex_union (Blob *b1, Blob *b2);
|
Blob *blob_convex_union (Blob *b1, Blob *b2);
|
||||||
|
Blob *blob_polygon (BlobPoint *points, int npoints);
|
||||||
|
Blob *blob_square (double xc, double yc, double xp, double yp, double xq, double yq);
|
||||||
|
Blob *blob_diamond (double xc, double yc, double xp, double yp, double xq, double yq);
|
||||||
Blob *blob_ellipse (double xc, double yc, double xp, double yp, double xq, double yq);
|
Blob *blob_ellipse (double xc, double yc, double xp, double yp, double xq, double yq);
|
||||||
void blob_bounds(Blob *b, int *x, int *y, int *width, int *height);
|
void blob_bounds(Blob *b, int *x, int *y, int *width, int *height);
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,8 @@
|
||||||
|
|
||||||
/* the Ink structures */
|
/* the Ink structures */
|
||||||
|
|
||||||
|
typedef Blob *(*BlobFunc) (double, double, double, double, double, double);
|
||||||
|
|
||||||
typedef struct _InkTool InkTool;
|
typedef struct _InkTool InkTool;
|
||||||
struct _InkTool
|
struct _InkTool
|
||||||
{
|
{
|
||||||
|
@ -64,14 +66,19 @@ struct _InkOptions
|
||||||
double sensitivity;
|
double sensitivity;
|
||||||
double tilt_sensitivity;
|
double tilt_sensitivity;
|
||||||
double tilt_angle;
|
double tilt_angle;
|
||||||
|
BlobFunc function;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _BrushWidget BrushWidget;
|
typedef struct _BrushWidget BrushWidget;
|
||||||
struct _BrushWidget
|
struct _BrushWidget
|
||||||
{
|
{
|
||||||
|
GtkWidget *widget;
|
||||||
gboolean state;
|
gboolean state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Global variable to store brush widget */
|
||||||
|
static BrushWidget *brush_widget;
|
||||||
|
|
||||||
/* undo blocks variables */
|
/* undo blocks variables */
|
||||||
static TileManager * undo_tiles = NULL;
|
static TileManager * undo_tiles = NULL;
|
||||||
|
|
||||||
|
@ -107,6 +114,15 @@ static void ink_cleanup (void);
|
||||||
|
|
||||||
static void ink_scale_update (GtkAdjustment *adjustment,
|
static void ink_scale_update (GtkAdjustment *adjustment,
|
||||||
gdouble *value);
|
gdouble *value);
|
||||||
|
static void ink_type_update (GtkWidget *radio_button,
|
||||||
|
BlobFunc function);
|
||||||
|
static GdkPixmap *blob_pixmap (GdkColormap *colormap,
|
||||||
|
GdkVisual *visual,
|
||||||
|
BlobFunc function);
|
||||||
|
static void paint_blob (GdkDrawable *drawable,
|
||||||
|
GdkGC *gc,
|
||||||
|
Blob *blob);
|
||||||
|
|
||||||
/* Rendering functions */
|
/* Rendering functions */
|
||||||
|
|
||||||
static void ink_set_paint_area (InkTool *ink_tool,
|
static void ink_set_paint_area (InkTool *ink_tool,
|
||||||
|
@ -153,18 +169,22 @@ static InkOptions *
|
||||||
create_ink_options ()
|
create_ink_options ()
|
||||||
{
|
{
|
||||||
GtkWidget *vbox;
|
GtkWidget *vbox;
|
||||||
|
GtkWidget *util_vbox;
|
||||||
GtkWidget *hbox;
|
GtkWidget *hbox;
|
||||||
GtkWidget *label;
|
GtkWidget *label;
|
||||||
|
GtkWidget *radio_button;
|
||||||
|
GtkWidget *pixmap_widget;
|
||||||
GtkWidget *slider;
|
GtkWidget *slider;
|
||||||
GtkWidget *aspect_frame;
|
GtkWidget *aspect_frame;
|
||||||
GtkWidget *darea;
|
GtkWidget *darea;
|
||||||
GtkAdjustment *adj;
|
GtkAdjustment *adj;
|
||||||
|
|
||||||
BrushWidget *brush_widget;
|
GdkPixmap *pixmap;
|
||||||
|
|
||||||
InkOptions *options;
|
InkOptions *options;
|
||||||
|
|
||||||
/* the new options structure */
|
/* the new options structure */
|
||||||
options = (InkOptions *) g_malloc (sizeof (InkOptions));
|
options = g_new (InkOptions, 1);
|
||||||
|
|
||||||
options->size = 3.0;
|
options->size = 3.0;
|
||||||
options->sensitivity = 1.0;
|
options->sensitivity = 1.0;
|
||||||
|
@ -172,6 +192,7 @@ create_ink_options ()
|
||||||
options->angle = 0.0;
|
options->angle = 0.0;
|
||||||
options->tilt_sensitivity = 1.0;
|
options->tilt_sensitivity = 1.0;
|
||||||
options->tilt_angle = 0.0;
|
options->tilt_angle = 0.0;
|
||||||
|
options->function = blob_ellipse;
|
||||||
|
|
||||||
/* the main vbox */
|
/* the main vbox */
|
||||||
vbox = gtk_vbox_new (FALSE, 1);
|
vbox = gtk_vbox_new (FALSE, 1);
|
||||||
|
@ -245,21 +266,80 @@ create_ink_options ()
|
||||||
(GtkSignalFunc) ink_scale_update,
|
(GtkSignalFunc) ink_scale_update,
|
||||||
&options->tilt_angle);
|
&options->tilt_angle);
|
||||||
|
|
||||||
|
/* Brush type radiobuttons */
|
||||||
|
|
||||||
|
hbox = gtk_hbox_new (FALSE, 2);
|
||||||
|
gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
|
||||||
|
|
||||||
|
util_vbox = gtk_vbox_new (FALSE, 2);
|
||||||
|
gtk_box_pack_start (GTK_BOX(hbox), util_vbox, FALSE, FALSE, 5);
|
||||||
|
|
||||||
|
label = gtk_label_new (_("Type:"));
|
||||||
|
gtk_box_pack_start (GTK_BOX (util_vbox), label, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
pixmap = blob_pixmap (gtk_widget_get_colormap (util_vbox),
|
||||||
|
gtk_widget_get_visual (util_vbox),
|
||||||
|
blob_ellipse);
|
||||||
|
|
||||||
|
pixmap_widget = gtk_pixmap_new (pixmap, NULL);
|
||||||
|
gdk_pixmap_unref (pixmap);
|
||||||
|
|
||||||
|
radio_button = gtk_radio_button_new (NULL);
|
||||||
|
gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
|
||||||
|
GTK_SIGNAL_FUNC (ink_type_update),
|
||||||
|
(gpointer)blob_ellipse);
|
||||||
|
|
||||||
|
gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
|
||||||
|
gtk_box_pack_start (GTK_BOX (util_vbox), radio_button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
pixmap = blob_pixmap (gtk_widget_get_colormap (util_vbox),
|
||||||
|
gtk_widget_get_visual (util_vbox),
|
||||||
|
blob_square);
|
||||||
|
|
||||||
|
pixmap_widget = gtk_pixmap_new (pixmap, NULL);
|
||||||
|
gdk_pixmap_unref (pixmap);
|
||||||
|
|
||||||
|
radio_button = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio_button));
|
||||||
|
gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
|
||||||
|
GTK_SIGNAL_FUNC (ink_type_update),
|
||||||
|
(gpointer)blob_square);
|
||||||
|
|
||||||
|
gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
|
||||||
|
gtk_box_pack_start (GTK_BOX (util_vbox), radio_button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
pixmap = blob_pixmap (gtk_widget_get_colormap (util_vbox),
|
||||||
|
gtk_widget_get_visual (util_vbox),
|
||||||
|
blob_diamond);
|
||||||
|
|
||||||
|
pixmap_widget = gtk_pixmap_new (pixmap, NULL);
|
||||||
|
gdk_pixmap_unref (pixmap);
|
||||||
|
|
||||||
|
radio_button = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio_button));
|
||||||
|
gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
|
||||||
|
GTK_SIGNAL_FUNC (ink_type_update),
|
||||||
|
(gpointer)blob_diamond);
|
||||||
|
|
||||||
|
gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
|
||||||
|
gtk_box_pack_start (GTK_BOX (util_vbox), radio_button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
/* Brush shape widget */
|
/* Brush shape widget */
|
||||||
|
|
||||||
brush_widget = g_new (BrushWidget, 1);
|
brush_widget = g_new (BrushWidget, 1);
|
||||||
brush_widget->state = FALSE;
|
brush_widget->state = FALSE;
|
||||||
|
|
||||||
hbox = gtk_hbox_new (FALSE, 2);
|
util_vbox = gtk_vbox_new (FALSE, 2);
|
||||||
gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
|
gtk_box_pack_start (GTK_BOX(hbox), util_vbox, FALSE, FALSE, 5);
|
||||||
|
|
||||||
label = gtk_label_new (_("Shape:"));
|
label = gtk_label_new (_("Shape:"));
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
gtk_box_pack_start (GTK_BOX (util_vbox), label, FALSE, FALSE, 0);
|
||||||
|
|
||||||
aspect_frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1.0, FALSE);
|
aspect_frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1.0, FALSE);
|
||||||
gtk_frame_set_shadow_type (GTK_FRAME(aspect_frame), GTK_SHADOW_IN);
|
gtk_frame_set_shadow_type (GTK_FRAME(aspect_frame), GTK_SHADOW_IN);
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), aspect_frame, TRUE, TRUE, 2);
|
gtk_box_pack_start (GTK_BOX (util_vbox), aspect_frame, TRUE, TRUE, 2);
|
||||||
|
|
||||||
darea = gtk_drawing_area_new();
|
darea = gtk_drawing_area_new();
|
||||||
|
brush_widget->widget = darea;
|
||||||
|
|
||||||
gtk_drawing_area_size (GTK_DRAWING_AREA(darea), 60, 60);
|
gtk_drawing_area_size (GTK_DRAWING_AREA(darea), 60, 60);
|
||||||
gtk_container_add (GTK_CONTAINER(aspect_frame), darea);
|
gtk_container_add (GTK_CONTAINER(aspect_frame), darea);
|
||||||
|
|
||||||
|
@ -320,24 +400,15 @@ static void
|
||||||
brush_widget_draw_brush (BrushWidget *brush_widget, GtkWidget *w,
|
brush_widget_draw_brush (BrushWidget *brush_widget, GtkWidget *w,
|
||||||
double xc, double yc, double radius)
|
double xc, double yc, double radius)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
Blob *b;
|
Blob *b;
|
||||||
|
|
||||||
b = blob_ellipse(xc,yc,
|
b = ink_options->function (xc,yc,
|
||||||
radius*cos(ink_options->angle),
|
radius*cos(ink_options->angle),
|
||||||
radius*sin(ink_options->angle),
|
radius*sin(ink_options->angle),
|
||||||
-(radius/ink_options->aspect)*sin(ink_options->angle),
|
-(radius/ink_options->aspect)*sin(ink_options->angle),
|
||||||
(radius/ink_options->aspect)*cos(ink_options->angle));
|
(radius/ink_options->aspect)*cos(ink_options->angle));
|
||||||
|
|
||||||
for (i=0;i<b->height;i++)
|
paint_blob (w->window, w->style->fg_gc[w->state],b);
|
||||||
{
|
|
||||||
if (b->data[i].left <= b->data[i].right)
|
|
||||||
gdk_draw_line (w->window,
|
|
||||||
w->style->fg_gc[w->state],
|
|
||||||
b->data[i].left,i+b->y,
|
|
||||||
b->data[i].right+1,i+b->y);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free (b);
|
g_free (b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,6 +502,69 @@ ink_scale_update (GtkAdjustment *adjustment, gdouble *value)
|
||||||
*value = adjustment->value;
|
*value = adjustment->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ink_type_update (GtkWidget *radio_button,
|
||||||
|
BlobFunc function)
|
||||||
|
{
|
||||||
|
if (GTK_TOGGLE_BUTTON (radio_button)->active)
|
||||||
|
ink_options->function = function;
|
||||||
|
|
||||||
|
gtk_widget_queue_draw (brush_widget->widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return a black-on white pixmap in the given colormap and
|
||||||
|
* visual that represents the BlobFunc 'function'
|
||||||
|
*/
|
||||||
|
static GdkPixmap *
|
||||||
|
blob_pixmap (GdkColormap *colormap,
|
||||||
|
GdkVisual *visual,
|
||||||
|
BlobFunc function)
|
||||||
|
{
|
||||||
|
GdkPixmap *pixmap;
|
||||||
|
GdkGC *black_gc, *white_gc;
|
||||||
|
GdkColor tmp_color;
|
||||||
|
Blob *blob;
|
||||||
|
|
||||||
|
pixmap = gdk_pixmap_new (NULL, 22, 21, visual->depth);
|
||||||
|
|
||||||
|
black_gc = gdk_gc_new (pixmap);
|
||||||
|
gdk_color_black (colormap, &tmp_color);
|
||||||
|
gdk_gc_set_foreground (black_gc, &tmp_color);
|
||||||
|
|
||||||
|
white_gc = gdk_gc_new (pixmap);
|
||||||
|
gdk_color_white (colormap, &tmp_color);
|
||||||
|
gdk_gc_set_foreground (white_gc, &tmp_color);
|
||||||
|
|
||||||
|
gdk_draw_rectangle (pixmap, white_gc, TRUE, 0, 0, 21, 20);
|
||||||
|
gdk_draw_rectangle (pixmap, black_gc, FALSE, 0, 0, 21, 20);
|
||||||
|
blob = (*function) (10, 10, 8, 0, 0, 8);
|
||||||
|
paint_blob (pixmap, black_gc, blob);
|
||||||
|
|
||||||
|
gdk_gc_unref (white_gc);
|
||||||
|
gdk_gc_unref (black_gc);
|
||||||
|
|
||||||
|
return pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draw a blob onto a drawable with the specified graphics context
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
paint_blob (GdkDrawable *drawable, GdkGC *gc,
|
||||||
|
Blob *blob)
|
||||||
|
{
|
||||||
|
int 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static Blob *
|
static Blob *
|
||||||
ink_pen_ellipse (gdouble x_center, gdouble y_center,
|
ink_pen_ellipse (gdouble x_center, gdouble y_center,
|
||||||
gdouble pressure, gdouble xtilt, gdouble ytilt)
|
gdouble pressure, gdouble xtilt, gdouble ytilt)
|
||||||
|
@ -484,9 +618,9 @@ ink_pen_ellipse (gdouble x_center, gdouble y_center,
|
||||||
radmin = SUBSAMPLE * size/aspect;
|
radmin = SUBSAMPLE * size/aspect;
|
||||||
if (radmin < 1.0) radmin = 1.0;
|
if (radmin < 1.0) radmin = 1.0;
|
||||||
|
|
||||||
return blob_ellipse(x_center * SUBSAMPLE, y_center * SUBSAMPLE,
|
return ink_options->function (x_center * SUBSAMPLE, y_center * SUBSAMPLE,
|
||||||
radmin*aspect*tcos, radmin*aspect*tsin,
|
radmin*aspect*tcos, radmin*aspect*tsin,
|
||||||
-radmin*tsin, radmin*tcos);
|
-radmin*tsin, radmin*tcos);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
184
app/tools/ink.c
184
app/tools/ink.c
|
@ -43,6 +43,8 @@
|
||||||
|
|
||||||
/* the Ink structures */
|
/* the Ink structures */
|
||||||
|
|
||||||
|
typedef Blob *(*BlobFunc) (double, double, double, double, double, double);
|
||||||
|
|
||||||
typedef struct _InkTool InkTool;
|
typedef struct _InkTool InkTool;
|
||||||
struct _InkTool
|
struct _InkTool
|
||||||
{
|
{
|
||||||
|
@ -64,14 +66,19 @@ struct _InkOptions
|
||||||
double sensitivity;
|
double sensitivity;
|
||||||
double tilt_sensitivity;
|
double tilt_sensitivity;
|
||||||
double tilt_angle;
|
double tilt_angle;
|
||||||
|
BlobFunc function;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _BrushWidget BrushWidget;
|
typedef struct _BrushWidget BrushWidget;
|
||||||
struct _BrushWidget
|
struct _BrushWidget
|
||||||
{
|
{
|
||||||
|
GtkWidget *widget;
|
||||||
gboolean state;
|
gboolean state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Global variable to store brush widget */
|
||||||
|
static BrushWidget *brush_widget;
|
||||||
|
|
||||||
/* undo blocks variables */
|
/* undo blocks variables */
|
||||||
static TileManager * undo_tiles = NULL;
|
static TileManager * undo_tiles = NULL;
|
||||||
|
|
||||||
|
@ -107,6 +114,15 @@ static void ink_cleanup (void);
|
||||||
|
|
||||||
static void ink_scale_update (GtkAdjustment *adjustment,
|
static void ink_scale_update (GtkAdjustment *adjustment,
|
||||||
gdouble *value);
|
gdouble *value);
|
||||||
|
static void ink_type_update (GtkWidget *radio_button,
|
||||||
|
BlobFunc function);
|
||||||
|
static GdkPixmap *blob_pixmap (GdkColormap *colormap,
|
||||||
|
GdkVisual *visual,
|
||||||
|
BlobFunc function);
|
||||||
|
static void paint_blob (GdkDrawable *drawable,
|
||||||
|
GdkGC *gc,
|
||||||
|
Blob *blob);
|
||||||
|
|
||||||
/* Rendering functions */
|
/* Rendering functions */
|
||||||
|
|
||||||
static void ink_set_paint_area (InkTool *ink_tool,
|
static void ink_set_paint_area (InkTool *ink_tool,
|
||||||
|
@ -153,18 +169,22 @@ static InkOptions *
|
||||||
create_ink_options ()
|
create_ink_options ()
|
||||||
{
|
{
|
||||||
GtkWidget *vbox;
|
GtkWidget *vbox;
|
||||||
|
GtkWidget *util_vbox;
|
||||||
GtkWidget *hbox;
|
GtkWidget *hbox;
|
||||||
GtkWidget *label;
|
GtkWidget *label;
|
||||||
|
GtkWidget *radio_button;
|
||||||
|
GtkWidget *pixmap_widget;
|
||||||
GtkWidget *slider;
|
GtkWidget *slider;
|
||||||
GtkWidget *aspect_frame;
|
GtkWidget *aspect_frame;
|
||||||
GtkWidget *darea;
|
GtkWidget *darea;
|
||||||
GtkAdjustment *adj;
|
GtkAdjustment *adj;
|
||||||
|
|
||||||
BrushWidget *brush_widget;
|
GdkPixmap *pixmap;
|
||||||
|
|
||||||
InkOptions *options;
|
InkOptions *options;
|
||||||
|
|
||||||
/* the new options structure */
|
/* the new options structure */
|
||||||
options = (InkOptions *) g_malloc (sizeof (InkOptions));
|
options = g_new (InkOptions, 1);
|
||||||
|
|
||||||
options->size = 3.0;
|
options->size = 3.0;
|
||||||
options->sensitivity = 1.0;
|
options->sensitivity = 1.0;
|
||||||
|
@ -172,6 +192,7 @@ create_ink_options ()
|
||||||
options->angle = 0.0;
|
options->angle = 0.0;
|
||||||
options->tilt_sensitivity = 1.0;
|
options->tilt_sensitivity = 1.0;
|
||||||
options->tilt_angle = 0.0;
|
options->tilt_angle = 0.0;
|
||||||
|
options->function = blob_ellipse;
|
||||||
|
|
||||||
/* the main vbox */
|
/* the main vbox */
|
||||||
vbox = gtk_vbox_new (FALSE, 1);
|
vbox = gtk_vbox_new (FALSE, 1);
|
||||||
|
@ -245,21 +266,80 @@ create_ink_options ()
|
||||||
(GtkSignalFunc) ink_scale_update,
|
(GtkSignalFunc) ink_scale_update,
|
||||||
&options->tilt_angle);
|
&options->tilt_angle);
|
||||||
|
|
||||||
|
/* Brush type radiobuttons */
|
||||||
|
|
||||||
|
hbox = gtk_hbox_new (FALSE, 2);
|
||||||
|
gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
|
||||||
|
|
||||||
|
util_vbox = gtk_vbox_new (FALSE, 2);
|
||||||
|
gtk_box_pack_start (GTK_BOX(hbox), util_vbox, FALSE, FALSE, 5);
|
||||||
|
|
||||||
|
label = gtk_label_new (_("Type:"));
|
||||||
|
gtk_box_pack_start (GTK_BOX (util_vbox), label, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
pixmap = blob_pixmap (gtk_widget_get_colormap (util_vbox),
|
||||||
|
gtk_widget_get_visual (util_vbox),
|
||||||
|
blob_ellipse);
|
||||||
|
|
||||||
|
pixmap_widget = gtk_pixmap_new (pixmap, NULL);
|
||||||
|
gdk_pixmap_unref (pixmap);
|
||||||
|
|
||||||
|
radio_button = gtk_radio_button_new (NULL);
|
||||||
|
gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
|
||||||
|
GTK_SIGNAL_FUNC (ink_type_update),
|
||||||
|
(gpointer)blob_ellipse);
|
||||||
|
|
||||||
|
gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
|
||||||
|
gtk_box_pack_start (GTK_BOX (util_vbox), radio_button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
pixmap = blob_pixmap (gtk_widget_get_colormap (util_vbox),
|
||||||
|
gtk_widget_get_visual (util_vbox),
|
||||||
|
blob_square);
|
||||||
|
|
||||||
|
pixmap_widget = gtk_pixmap_new (pixmap, NULL);
|
||||||
|
gdk_pixmap_unref (pixmap);
|
||||||
|
|
||||||
|
radio_button = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio_button));
|
||||||
|
gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
|
||||||
|
GTK_SIGNAL_FUNC (ink_type_update),
|
||||||
|
(gpointer)blob_square);
|
||||||
|
|
||||||
|
gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
|
||||||
|
gtk_box_pack_start (GTK_BOX (util_vbox), radio_button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
pixmap = blob_pixmap (gtk_widget_get_colormap (util_vbox),
|
||||||
|
gtk_widget_get_visual (util_vbox),
|
||||||
|
blob_diamond);
|
||||||
|
|
||||||
|
pixmap_widget = gtk_pixmap_new (pixmap, NULL);
|
||||||
|
gdk_pixmap_unref (pixmap);
|
||||||
|
|
||||||
|
radio_button = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio_button));
|
||||||
|
gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
|
||||||
|
GTK_SIGNAL_FUNC (ink_type_update),
|
||||||
|
(gpointer)blob_diamond);
|
||||||
|
|
||||||
|
gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
|
||||||
|
gtk_box_pack_start (GTK_BOX (util_vbox), radio_button, FALSE, FALSE, 0);
|
||||||
|
|
||||||
/* Brush shape widget */
|
/* Brush shape widget */
|
||||||
|
|
||||||
brush_widget = g_new (BrushWidget, 1);
|
brush_widget = g_new (BrushWidget, 1);
|
||||||
brush_widget->state = FALSE;
|
brush_widget->state = FALSE;
|
||||||
|
|
||||||
hbox = gtk_hbox_new (FALSE, 2);
|
util_vbox = gtk_vbox_new (FALSE, 2);
|
||||||
gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
|
gtk_box_pack_start (GTK_BOX(hbox), util_vbox, FALSE, FALSE, 5);
|
||||||
|
|
||||||
label = gtk_label_new (_("Shape:"));
|
label = gtk_label_new (_("Shape:"));
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
gtk_box_pack_start (GTK_BOX (util_vbox), label, FALSE, FALSE, 0);
|
||||||
|
|
||||||
aspect_frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1.0, FALSE);
|
aspect_frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1.0, FALSE);
|
||||||
gtk_frame_set_shadow_type (GTK_FRAME(aspect_frame), GTK_SHADOW_IN);
|
gtk_frame_set_shadow_type (GTK_FRAME(aspect_frame), GTK_SHADOW_IN);
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), aspect_frame, TRUE, TRUE, 2);
|
gtk_box_pack_start (GTK_BOX (util_vbox), aspect_frame, TRUE, TRUE, 2);
|
||||||
|
|
||||||
darea = gtk_drawing_area_new();
|
darea = gtk_drawing_area_new();
|
||||||
|
brush_widget->widget = darea;
|
||||||
|
|
||||||
gtk_drawing_area_size (GTK_DRAWING_AREA(darea), 60, 60);
|
gtk_drawing_area_size (GTK_DRAWING_AREA(darea), 60, 60);
|
||||||
gtk_container_add (GTK_CONTAINER(aspect_frame), darea);
|
gtk_container_add (GTK_CONTAINER(aspect_frame), darea);
|
||||||
|
|
||||||
|
@ -320,24 +400,15 @@ static void
|
||||||
brush_widget_draw_brush (BrushWidget *brush_widget, GtkWidget *w,
|
brush_widget_draw_brush (BrushWidget *brush_widget, GtkWidget *w,
|
||||||
double xc, double yc, double radius)
|
double xc, double yc, double radius)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
Blob *b;
|
Blob *b;
|
||||||
|
|
||||||
b = blob_ellipse(xc,yc,
|
b = ink_options->function (xc,yc,
|
||||||
radius*cos(ink_options->angle),
|
radius*cos(ink_options->angle),
|
||||||
radius*sin(ink_options->angle),
|
radius*sin(ink_options->angle),
|
||||||
-(radius/ink_options->aspect)*sin(ink_options->angle),
|
-(radius/ink_options->aspect)*sin(ink_options->angle),
|
||||||
(radius/ink_options->aspect)*cos(ink_options->angle));
|
(radius/ink_options->aspect)*cos(ink_options->angle));
|
||||||
|
|
||||||
for (i=0;i<b->height;i++)
|
paint_blob (w->window, w->style->fg_gc[w->state],b);
|
||||||
{
|
|
||||||
if (b->data[i].left <= b->data[i].right)
|
|
||||||
gdk_draw_line (w->window,
|
|
||||||
w->style->fg_gc[w->state],
|
|
||||||
b->data[i].left,i+b->y,
|
|
||||||
b->data[i].right+1,i+b->y);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free (b);
|
g_free (b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,6 +502,69 @@ ink_scale_update (GtkAdjustment *adjustment, gdouble *value)
|
||||||
*value = adjustment->value;
|
*value = adjustment->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ink_type_update (GtkWidget *radio_button,
|
||||||
|
BlobFunc function)
|
||||||
|
{
|
||||||
|
if (GTK_TOGGLE_BUTTON (radio_button)->active)
|
||||||
|
ink_options->function = function;
|
||||||
|
|
||||||
|
gtk_widget_queue_draw (brush_widget->widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return a black-on white pixmap in the given colormap and
|
||||||
|
* visual that represents the BlobFunc 'function'
|
||||||
|
*/
|
||||||
|
static GdkPixmap *
|
||||||
|
blob_pixmap (GdkColormap *colormap,
|
||||||
|
GdkVisual *visual,
|
||||||
|
BlobFunc function)
|
||||||
|
{
|
||||||
|
GdkPixmap *pixmap;
|
||||||
|
GdkGC *black_gc, *white_gc;
|
||||||
|
GdkColor tmp_color;
|
||||||
|
Blob *blob;
|
||||||
|
|
||||||
|
pixmap = gdk_pixmap_new (NULL, 22, 21, visual->depth);
|
||||||
|
|
||||||
|
black_gc = gdk_gc_new (pixmap);
|
||||||
|
gdk_color_black (colormap, &tmp_color);
|
||||||
|
gdk_gc_set_foreground (black_gc, &tmp_color);
|
||||||
|
|
||||||
|
white_gc = gdk_gc_new (pixmap);
|
||||||
|
gdk_color_white (colormap, &tmp_color);
|
||||||
|
gdk_gc_set_foreground (white_gc, &tmp_color);
|
||||||
|
|
||||||
|
gdk_draw_rectangle (pixmap, white_gc, TRUE, 0, 0, 21, 20);
|
||||||
|
gdk_draw_rectangle (pixmap, black_gc, FALSE, 0, 0, 21, 20);
|
||||||
|
blob = (*function) (10, 10, 8, 0, 0, 8);
|
||||||
|
paint_blob (pixmap, black_gc, blob);
|
||||||
|
|
||||||
|
gdk_gc_unref (white_gc);
|
||||||
|
gdk_gc_unref (black_gc);
|
||||||
|
|
||||||
|
return pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draw a blob onto a drawable with the specified graphics context
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
paint_blob (GdkDrawable *drawable, GdkGC *gc,
|
||||||
|
Blob *blob)
|
||||||
|
{
|
||||||
|
int 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static Blob *
|
static Blob *
|
||||||
ink_pen_ellipse (gdouble x_center, gdouble y_center,
|
ink_pen_ellipse (gdouble x_center, gdouble y_center,
|
||||||
gdouble pressure, gdouble xtilt, gdouble ytilt)
|
gdouble pressure, gdouble xtilt, gdouble ytilt)
|
||||||
|
@ -484,9 +618,9 @@ ink_pen_ellipse (gdouble x_center, gdouble y_center,
|
||||||
radmin = SUBSAMPLE * size/aspect;
|
radmin = SUBSAMPLE * size/aspect;
|
||||||
if (radmin < 1.0) radmin = 1.0;
|
if (radmin < 1.0) radmin = 1.0;
|
||||||
|
|
||||||
return blob_ellipse(x_center * SUBSAMPLE, y_center * SUBSAMPLE,
|
return ink_options->function (x_center * SUBSAMPLE, y_center * SUBSAMPLE,
|
||||||
radmin*aspect*tcos, radmin*aspect*tsin,
|
radmin*aspect*tcos, radmin*aspect*tsin,
|
||||||
-radmin*tsin, radmin*tcos);
|
-radmin*tsin, radmin*tcos);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in New Issue