Changed:-

Fri Mar 12 21:30:57 GMT 1999 Andy Thomas <alt@gimp.org>

	Changed:-

	* app/bezier_select.c
	* app/paths_dialog.c

	Some code cleanups and bug fixes. Fixed problem with "copy" path
	producing very long names.

	Added functionality to import/export paths to files. (It was
	there before!)

	Also added some new bezier_stroke code that Shuji Narazaki posted
	to the gimp-devel list.

	* plug-ins/plugindetails/plugindetails.c

	Removed unwanted <regex.h>.
	Thanks to Tan Koan-Sin <freedom@csie.nctu.edu.tw> for pointing
	this out.
This commit is contained in:
GMT 1999 Andy Thomas 1999-03-12 22:04:30 +00:00 committed by Andy Thomas
parent 339f653a74
commit 7383354574
9 changed files with 1177 additions and 604 deletions

View File

@ -1,3 +1,26 @@
Fri Mar 12 21:30:57 GMT 1999 Andy Thomas <alt@gimp.org>
Changed:-
* app/bezier_select.c
* app/paths_dialog.c
Some code cleanups and bug fixes. Fixed problem with "copy" path
producing very long names.
Added functionality to import/export paths to files. (It was
there before!)
Also added some new bezier_stroke code that Shuji Narazaki posted
to the gimp-devel list.
* plug-ins/plugindetails/plugindetails.c
Removed unwanted <regex.h>.
Thanks to Tan Koan-Sin <freedom@csie.nctu.edu.tw> for pointing
this out.
Fri Mar 12 22:15:49 CET 1999 Marc Lehmann <pcg@goof.com>
* libgimp/gimp.c: split gimp_quit into two functions, gimp_quit

View File

@ -108,6 +108,8 @@ static GSList * bezier_insert_in_list (GSList *, int);
static int test_add_point_on_segment (BezierSelect *, BezierPoint *, int, int, int, int, int);
static void bezier_to_sel_internal (BezierSelect *, Tool *, GDisplay *, gint, gint);
static void bezier_stack_points (BezierSelect *, GdkPoint *, int);
static gboolean stroke_interpolatable (int, int, int, int, gdouble);
static void bezier_stack_points_aux (GdkPoint *, int, int, gdouble);
static BezierMatrix basis =
{
@ -1710,197 +1712,6 @@ bezier_paste_bezierselect_to_current(GDisplay *gdisp,BezierSelect *bsel)
}
}
static GtkWidget *file_dlg = 0;
static int load_store;
FILE *f;
static void bezier_buffer_save_foreach(GtkWidget *w,
gpointer client_data)
{
PasteNamedDlg *pn_dlg;
BezierNamedBuffer * nb;
BezierPoint *pt;
int i;
pn_dlg = (PasteNamedDlg *) client_data;
nb = (BezierNamedBuffer *) gtk_object_get_user_data (GTK_OBJECT (w));
fprintf(f, "Name: %s\n", nb->name);
fprintf(f, "#POINTS: %d\n", nb->sel->num_points);
fprintf(f, "CLOSED: %d\n", nb->sel->closed==1?1:0);
fprintf(f, "DRAW: %d\n", nb->sel->draw);
fprintf(f, "STATE: %d\n", nb->sel->state);
pt = nb->sel->points;
for(i=0; i< nb->sel->num_points; i++)
{
fprintf(f,"TYPE: %d X: %d Y: %d\n", pt->type, pt->x, pt->y);
pt = pt->next;
}
}
static void file_ok_callback(GtkWidget * widget, gpointer client_data)
{
GtkFileSelection *fs;
char* filename;
fs = GTK_FILE_SELECTION (file_dlg);
filename = gtk_file_selection_get_filename (fs);
if (load_store)
{
PasteNamedDlg *pn_dlg;
BezierNamedBuffer * nb;
pn_dlg = (PasteNamedDlg *) client_data;
f = fopen(filename, "rb");
printf(_("reading %s\n"), filename);
while(!feof(f))
{
char txt[30];
int val, x, y, type, closed, i, draw, state;
/*
fscanf(f, "%s", txt);
if (strcmp("BEZIER_EXTENDS",txt))
{
GString *s;
fclose(f);
s = g_string_new (_("Open failed: "));
g_string_append (s, _("Bezier Load"));
g_message (s->str);
g_string_free (s, TRUE);
return;
}
*/
fscanf(f, "Name: %s\n", txt);
fscanf(f, "#POINTS: %d\n", &val);
fscanf(f, "CLOSED: %d\n", &closed);
fscanf(f, "DRAW: %d\n", &draw);
fscanf(f, "STATE: %d\n", &state);
nb = (BezierNamedBuffer *) g_malloc (sizeof(BezierNamedBuffer));
nb->name = g_strdup ((char *) txt);
nb->sel = (BezierSelect *) g_malloc( sizeof (BezierSelect));
if (nb->sel == NULL)
{
return;
}
nb->sel->closed = 0;
nb->sel->points = NULL; /* initially there are no points */
nb->sel->cur_anchor = NULL;
nb->sel->cur_control = NULL;
nb->sel->last_point = NULL;
nb->sel->num_points = 0; /* intially there are no points */
nb->sel->mask = NULL; /* empty mask */
nb->sel->scanlines = NULL;
for(i=0; i< val; i++)
{
fscanf(f,"TYPE: %d X: %d Y: %d\n", &type, &x, &y);
bezier_add_point( nb->sel, type, x, y);
}
if ( closed )
{
nb->sel->last_point->next = nb->sel->points;
nb->sel->points->prev = nb->sel->last_point;
nb->sel->cur_anchor = nb->sel->points;
nb->sel->cur_control = nb->sel-> points->next;
nb->sel->closed = 1;
}
nb->sel->state = state;
nb->sel->draw = draw;
bezier_named_buffers = g_slist_append (bezier_named_buffers, (void *) nb);
}
fclose(f);
}
else
{
PasteNamedDlg *pn_dlg;
f = fopen(filename, "wb");
if (NULL == f)
{
perror(filename);
return;
}
pn_dlg = (PasteNamedDlg *) client_data;
/*
fprintf(f,"BEZIER_EXTENDS\n");
*/
gtk_container_foreach ((GtkContainer*) pn_dlg->list,
bezier_buffer_save_foreach,
client_data);
fclose(f);
}
gtk_widget_hide (file_dlg);
}
static void file_cancel_callback(GtkWidget * widget, gpointer data)
{
gtk_widget_hide (file_dlg);
}
static void make_file_dlg(gpointer data)
{
file_dlg = gtk_file_selection_new (_("Load/Store Bezier Curves"));
gtk_window_position (GTK_WINDOW (file_dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION (file_dlg)->cancel_button),
"clicked", (GtkSignalFunc) file_cancel_callback, data);
gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION (file_dlg)->ok_button),
"clicked", (GtkSignalFunc) file_ok_callback, data);
}
static void load_callback(GtkWidget * widget, gpointer data)
{
if (!file_dlg)
{
make_file_dlg(data);
}
else
{
if (GTK_WIDGET_VISIBLE(file_dlg))
return;
}
gtk_window_set_title(GTK_WINDOW (file_dlg), _("Load Bezier Curves"));
load_store = 1;
gtk_widget_show (file_dlg);
}
static void store_callback(GtkWidget * widget, gpointer data)
{
if (!file_dlg)
{
make_file_dlg(data);
}
else
{
if (GTK_WIDGET_VISIBLE(file_dlg))
return;
}
gtk_window_set_title(GTK_WINDOW (file_dlg), _("Store Bezier Curves"));
load_store = 0;
gtk_widget_show (file_dlg);
}
static void
bezier_to_sel_internal(BezierSelect *bezier_sel,
Tool *tool,
@ -2191,6 +2002,25 @@ void bezier_select_mode(gint mode)
ModeEdit = mode;
}
/* The curve has to be closed to do a selection. */
void
bezier_to_selection(BezierSelect *bezier_sel,
GDisplay *gdisp)
{
/* Call the internal function */
if(!bezier_sel->closed)
{
g_warning("Curve not closed");
return;
}
/* force the passed selection to be the current selection..*/
/* This loads it into curSel for this image */
bezier_paste_bezierselect_to_current(gdisp,bezier_sel);
bezier_to_sel_internal(curSel,curTool,gdisp,ADD,1);
}
void printSel( BezierSelect *sel)
{
BezierPoint *pt;
@ -2212,61 +2042,166 @@ void printSel( BezierSelect *sel)
printf("state: %d\n", sel->state);
}
static gdouble *stroke_points = NULL;
static gint num_stroke_points = 0;
static gdouble *stroke_points = NULL;
static gint num_stroke_points = 0; /* num of valid points */
static gint len_stroke_points = 0; /* allocated length */
/* check whether vectors (offx, offy), (l_offx, l_offy) have the same angle. */
static gboolean
stroke_interpolatable (int offx, int offy, int l_offx, int l_offy, gdouble error)
{
if ((offx == l_offx) & (offy == l_offy))
return TRUE;
else if ((offx == 0) | (l_offx == 0))
if (offx == l_offx)
return ((0 <= offy) & (0 <= offy)) | ((offy < 0) & (l_offy < 0));
else
return FALSE;
else if ((offy == 0) | (l_offy == 0))
if (offy == l_offy)
return ((0 < offx) & (0 < l_offx)) | ((offx < 0) & (l_offx < 0));
else
return FALSE;
/* At this point, we can assert: offx, offy, l_offx, l_offy != 0 */
else if (((0 < offx) & (0 < l_offx)) | ((offx < 0) & (l_offx < 0)))
{
gdouble grad1, grad2;
if (ABS (offy) < ABS (offx))
{
grad1 = (gdouble) offy / (gdouble) offx;
grad2 = (gdouble) l_offy / (gdouble) l_offx;
}
else
{
grad1 = (gdouble) offx / (gdouble) offy;
grad2 = (gdouble) l_offx / (gdouble) l_offy;
}
/* printf ("error: %f / %f\n", ABS (grad1 - grad2), error); */
return (ABS (grad1 - grad2) <= error);
}
else
return FALSE;
}
static void
bezier_stack_points_aux (GdkPoint *points,
int start,
int end,
gdouble error)
{
const gint expand_size = 32;
gint med;
gint offx, offy, l_offx, l_offy;
if (stroke_points == NULL)
return;
/* BASE CASE: stack the end point */
if (end - start <= 1)
{
if ((stroke_points[num_stroke_points * 2 - 2] == points[end].x)
&& (stroke_points[num_stroke_points * 2 - 1] == points[end].y))
return;
num_stroke_points++;
if (len_stroke_points <= num_stroke_points)
{
len_stroke_points += expand_size;
stroke_points = g_renew (double, stroke_points, 2 * len_stroke_points);
if (stroke_points == NULL)
{
len_stroke_points = num_stroke_points = 0;
return;
}
}
stroke_points[num_stroke_points * 2 - 2] = points[end].x;
stroke_points[num_stroke_points * 2 - 1] = points[end].y;
return;
}
if (end - start <= 32)
{
gint i;
for (i = start+ 1; i <= end; i++)
bezier_stack_points_aux (points, i, i, 0);
return;
}
/* Otherwise, check whether to divide the segment recursively */
offx = points[end].x - points[start].x;
offy = points[end].y - points[start].y;
med = (end + start) / 2;
l_offx = points[med].x - points[start].x;
l_offy = points[med].y - points[start].y;
if (! stroke_interpolatable (offx, offy, l_offx, l_offy, error))
{
bezier_stack_points_aux (points, start, med, error);
bezier_stack_points_aux (points, med, end, error);
return;
}
l_offx = points[end].x - points[med].x;
l_offy = points[end].y - points[med].y;
if (! stroke_interpolatable (offx, offy, l_offx, l_offy, error))
{
bezier_stack_points_aux (points, start, med, error);
bezier_stack_points_aux (points, med, end, error);
return;
}
/* Now, the curve can be represented by a points pair: (start, end).
So, add the last point to stroke_points. */
bezier_stack_points_aux (points, end, end, 0);
}
static void
bezier_stack_points (BezierSelect *bezier_sel,
GdkPoint *points,
int npoints)
{
int i, j;
gint i;
gint expand_size = 32;
gint minx, maxx, miny, maxy;
gdouble error;
if (stroke_points == NULL)
if (npoints < 2) /* Does this happen? */
return;
if (stroke_points == NULL) /* initialize it here */
{
j = 0;
num_stroke_points = npoints / 2;
stroke_points = g_new (double, 2 * num_stroke_points );
}
else
{
j = num_stroke_points * 2;
num_stroke_points += npoints / 2;
stroke_points = g_renew (double, stroke_points, 2 * num_stroke_points);
num_stroke_points = 0;
len_stroke_points = expand_size;
stroke_points = g_new (double, 2 * len_stroke_points);
}
/* copy points into stroke_points SPARSELY */
for (i = 0; i < npoints / 2 - 1; i++)
maxx = minx = points[0].x;
maxy = miny = points[0].y;
for (i = 1; i < npoints; i++)
{
stroke_points[j++] = points[i * 2].x;
stroke_points[j++] = points[i * 2].y;
if (points[i].x < minx)
minx = points[i].x;
else if (maxx < points[i].x)
maxx = points[i].x;
if (points[i].y < miny)
miny = points[i].x;
else if (maxy < points[i].y)
maxy = points[i].y;
}
/* the last point should be included anyway */
stroke_points[num_stroke_points * 2 - 2] = points[npoints - 1].x;
stroke_points[num_stroke_points * 2 - 1] = points[npoints - 1].y;
/* allow one pixel fluctuation */
error = 2.0 / MAX(maxx - minx, maxy - miny);
/* add the start point */
bezier_stack_points_aux (points, 0, 0, 0);
/* divide segments recursively */
bezier_stack_points_aux (points, 0, npoints - 1, error);
/* printf ("npoints: %d\n", npoints); */
}
/* The curve has to be closed to do a selection. */
void
bezier_to_selection(BezierSelect *bezier_sel,
GDisplay *gdisp)
{
/* Call the internal function */
if(!bezier_sel->closed)
{
g_warning("Curve not closed");
return;
}
/* force the passed selection to be the current selection..*/
/* This loads it into curSel for this image */
bezier_paste_bezierselect_to_current(gdisp,bezier_sel);
bezier_to_sel_internal(curSel,curTool,gdisp,ADD,1);
}
void
bezier_stroke (BezierSelect *bezier_sel,
GDisplay *gdisp,
@ -2277,6 +2212,7 @@ bezier_stroke (BezierSelect *bezier_sel,
int num_points;
Argument *return_vals;
int nreturn_vals;
int redraw = FALSE;
/* stack points */
points = bezier_sel->points;
@ -2301,8 +2237,10 @@ bezier_stroke (BezierSelect *bezier_sel,
else
{
if (bezier_sel->closed)
num_points--;
{
redraw = TRUE;
num_points--;
}
while (num_points >= 4)
{
bezier_draw_segment (bezier_sel, points,
@ -2316,18 +2254,33 @@ bezier_stroke (BezierSelect *bezier_sel,
}
}
return_vals = procedural_db_run_proc ("gimp_paintbrush",
&nreturn_vals,
PDB_DRAWABLE, drawable_ID (gimage_active_drawable (gdisp->gimage)),
PDB_FLOAT, (gdouble) 0,
PDB_INT32, (gint32) num_stroke_points * 2,
PDB_FLOATARRAY, stroke_points,
PDB_END);
if (stroke_points)
{
return_vals = procedural_db_run_proc ("gimp_paintbrush",
&nreturn_vals,
PDB_DRAWABLE, drawable_ID (gimage_active_drawable (gdisp->gimage)),
PDB_FLOAT, (gdouble) 0,
PDB_INT32, (gint32) num_stroke_points * 2,
PDB_FLOATARRAY, stroke_points,
PDB_END);
if (return_vals[0].value.pdb_int == PDB_SUCCESS)
{
if (redraw)
{
/* FIXME: how to update the image? */
}
gdisplays_flush ();
}
else
g_message (_("Paintbrush operation failed."));
procedural_db_destroy_args (return_vals, nreturn_vals);
g_free (stroke_points);
}
/* printf ("num_stroke_points: %d\ndone.\n", num_stroke_points); */
g_free (stroke_points);
stroke_points = NULL;
num_stroke_points = 0;
gdisplays_flush ();
return;
len_stroke_points = num_stroke_points = 0;
}

View File

@ -20,6 +20,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include "gdk/gdkkeysyms.h"
#include "appenv.h"
#include "draw_core.h"
@ -77,6 +79,10 @@ typedef struct {
int image_width, image_height;
int gimage_width, gimage_height;
/* pixmaps for the no preview bitmap */
GdkPixmap * pixmap_normal;
GdkPixmap * pixmap_selected;
/* state information */
gint selsigid;
GimpImage * gimage;
@ -118,7 +124,8 @@ static void paths_dialog_new_point_callback (GtkWidget *, gpointer);
static void paths_dialog_add_point_callback (GtkWidget *, gpointer);
static void paths_dialog_delete_point_callback (GtkWidget *, gpointer);
static void paths_dialog_edit_point_callback (GtkWidget *, gpointer);
static void paths_dialog_import_path_callback (GtkWidget *, gpointer);
static void paths_dialog_export_path_callback (GtkWidget *, gpointer);
#define NEW_PATH_BUTTON 1
#define DUP_PATH_BUTTON 2
@ -138,6 +145,10 @@ static MenuItem paths_ops[] =
paths_dialog_stroke_path_callback, NULL, NULL, NULL },
{ N_("Delete Path"), 'D', GDK_CONTROL_MASK,
paths_dialog_delete_path_callback, NULL, NULL, NULL },
{ N_("Import Path"), 'I', GDK_CONTROL_MASK,
paths_dialog_import_path_callback, NULL, NULL, NULL },
{ N_("Export Path"), 'E', GDK_CONTROL_MASK,
paths_dialog_export_path_callback, NULL, NULL, NULL },
{ NULL, 0, 0, NULL, NULL, NULL, NULL }
};
@ -317,11 +328,11 @@ GtkWidget * paths_dialog_create()
paths_ops_button_set_sensitive(DUP_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(DEL_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(STROKE_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_ADD_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_DEL_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_NEW_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_EDIT_BUTTON,FALSE);
point_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,FALSE);
}
return paths_dialog->vbox;
@ -332,6 +343,10 @@ static void paths_dialog_realized(GtkWidget *widget)
GdkColormap *colormap;
gchar dash_list[2]= {3,3};
/* Help out small displays */
if(preview_size < 64)
dash_list[1] = 1;
paths_dialog->gc = gdk_gc_new(widget->window);
gdk_gc_set_dashes(paths_dialog->gc,2,dash_list,2);
colormap = gtk_widget_get_colormap(paths_dialog->paths_list);
@ -384,15 +399,107 @@ bzpath_dialog_new(gint name_seed, gpointer udata)
return bzp;
}
/* Always return a copy that must be freed later */
static gchar *
strip_off_cnumber(gchar *str)
{
gchar * hashptr;
gint num;
gchar * copy;
if(!str)
return str;
copy = g_strdup(str);
if((hashptr = strrchr(copy,'#')) && /* have a hash */
strlen(hashptr) > 0 && /* followed by something */
(num = atoi(hashptr+1)) > 0 && /* which is a number */
((int)log10(num) + 1) == strlen(hashptr+1)) /* which is at the end */
{
gchar * tstr;
/* Has a #<number> */
*hashptr = '\0';
tstr = g_strdup(copy);
g_free(copy);
copy = tstr;
}
return copy;
}
/* Return NULL is already unique else a unique string */
static gchar *
unique_name(gchar *cstr)
{
GSList *tlist;
PATHIMAGELISTP plp;
gboolean unique = TRUE;
gchar *copy_cstr;
gchar *copy_test;
gchar *stripped_copy;
gint counter = 1;
/* Get bzpath structure */
plp = paths_dialog->current_path_list;
if(!plp)
return NULL;
tlist = plp->bz_paths;
while(tlist)
{
gchar *test_str = ((BZPATHP)(tlist->data))->name->str;
if(strcmp(cstr,test_str) == 0)
{
unique = FALSE;
break;
}
tlist = g_slist_next(tlist);
}
if(unique)
{
return NULL;
}
/* OK Clashes with something */
/* restart scan to find unique name */
stripped_copy = strip_off_cnumber(cstr);
copy_cstr = g_strdup_printf("%s#%d",stripped_copy,counter++);
tlist = plp->bz_paths;
while(tlist)
{
copy_test = ((BZPATHP)(tlist->data))->name->str;
if(strcmp(copy_cstr,copy_test) == 0)
{
g_free(copy_cstr);
copy_cstr = g_strdup_printf("%s#%d",stripped_copy,counter++);
tlist = plp->bz_paths;
continue;
}
tlist = g_slist_next(tlist);
}
g_free(stripped_copy);
return copy_cstr;
}
static BZPATHP
bzpath_copy(BZPATHP bzp)
{
BZPATHP bzp_copy = g_new0(BZPATH,1);
GString *s = g_string_new (NULL);
gchar *ext;
g_string_sprintf (s, "%s copy",bzp->name->str);
bzp_copy->name = s;
ext = unique_name(bzp->name->str);
bzp_copy->name = g_string_new(ext);
g_free(ext);
bzp_copy->closed = bzp->closed;
bzp_copy->state = bzp->state;
bzp_copy->bezier_details = bzpoints_copy(bzp->bezier_details);
@ -509,6 +616,8 @@ bz_change_name_row_to(gint row,gchar *text)
static void
paths_set_dash_line(GdkGC *gc,gboolean state)
{
gdk_gc_set_foreground(paths_dialog->gc, &paths_dialog->black);
if(state)
{
gdk_gc_set_line_attributes(gc,0,GDK_LINE_ON_OFF_DASH,GDK_CAP_BUTT,GDK_JOIN_ROUND);
@ -541,8 +650,6 @@ clear_pixmap_preview(PATHWIDGETP pwidget)
rgb_buf,
(paths_dialog->image_width + 4)*3);
gdk_gc_set_foreground(paths_dialog->gc, &paths_dialog->black);
paths_set_dash_line(paths_dialog->gc,FALSE);
gdk_draw_rectangle(pwidget->paths_pixmap,
@ -582,14 +689,26 @@ void paths_add_path(BZPATHP bzp,gint insrow)
}
else
{
pwidget->paths_pixmap =
gdk_pixmap_create_from_data (paths_dialog->vbox->window,
path_bits,
paths_dialog->image_width,
paths_dialog->image_height,
-1,
&paths_dialog->vbox->style->fg[GTK_STATE_SELECTED],
&paths_dialog->vbox->style->bg[GTK_STATE_SELECTED]);
if(!paths_dialog->pixmap_normal)
{
paths_dialog->pixmap_normal =
gdk_pixmap_create_from_data (paths_dialog->vbox->window,
path_bits,
paths_dialog->image_width,
paths_dialog->image_height,
-1,
&paths_dialog->vbox->style->fg[GTK_STATE_SELECTED],
&paths_dialog->vbox->style->bg[GTK_STATE_SELECTED]);
paths_dialog->pixmap_selected =
gdk_pixmap_create_from_data (paths_dialog->vbox->window,
path_bits,
paths_dialog->image_width,
paths_dialog->image_height,
-1,
&paths_dialog->vbox->style->fg[GTK_STATE_NORMAL],
&paths_dialog->vbox->style->bg[GTK_STATE_SELECTED]);
}
pwidget->paths_pixmap = paths_dialog->pixmap_normal;
}
gtk_clist_set_row_height(GTK_CLIST(paths_dialog->paths_list),
@ -737,20 +856,6 @@ paths_select_row(GtkWidget *widget,
bezier_paste_bezierselect_to_current(gdisp,bsel);
paths_update_preview(bsel);
beziersel_free(bsel);
/* Draw white as the border */
/* gdk_gc_set_foreground(paths_dialog->gc, &paths_dialog->black); */
/* gdk_draw_rectangle(pwidget->paths_pixmap, */
/* paths_dialog->gc, FALSE, 0, 0, */
/* paths_dialog->image_width+3, */
/* paths_dialog->image_height+3); */
/* gdk_draw_rectangle(pwidget->paths_pixmap, */
/* paths_dialog->gc, FALSE, 1, 1, */
/* paths_dialog->image_width+1, */
/* paths_dialog->image_height+1); */
}
static void
@ -766,19 +871,6 @@ paths_unselect_row(GtkWidget *widget,
if(!pwidget)
return;
/* gdk_gc_set_foreground(paths_dialog->gc, &paths_dialog->white); */
/* gdk_draw_rectangle(pwidget->paths_pixmap, */
/* paths_dialog->gc, FALSE, 0, 0, */
/* paths_dialog->image_width+3, */
/* paths_dialog->image_height+3); */
/* gdk_draw_rectangle(pwidget->paths_pixmap, */
/* paths_dialog->gc, FALSE, 1, 1, */
/* paths_dialog->image_width+1, */
/* paths_dialog->image_height+1); */
}
void
@ -796,6 +888,19 @@ paths_dialog_update (GimpImage* gimage)
* under our feet.
*/
if(!gimp_image_get_paths(gimage))
{
/* No paths is this layer */
paths_ops_button_set_sensitive(DUP_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(DEL_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(STROKE_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_ADD_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_DEL_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_NEW_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_EDIT_BUTTON,FALSE);
}
if (paths_dialog->gimage == gimage &&
paths_dialog->current_path_list == (PATHIMAGELISTP)gimp_image_get_paths(gimage))
return;
@ -827,11 +932,11 @@ paths_dialog_update (GimpImage* gimage)
paths_ops_button_set_sensitive(DUP_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(DEL_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(STROKE_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_ADD_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_DEL_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_NEW_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_EDIT_BUTTON,FALSE);
point_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,FALSE);
return;
}
else
@ -839,11 +944,11 @@ paths_dialog_update (GimpImage* gimage)
paths_ops_button_set_sensitive(DUP_PATH_BUTTON,TRUE);
paths_ops_button_set_sensitive(DEL_PATH_BUTTON,TRUE);
paths_ops_button_set_sensitive(STROKE_PATH_BUTTON,TRUE);
paths_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,TRUE);
point_ops_button_set_sensitive(POINT_ADD_BUTTON,TRUE);
point_ops_button_set_sensitive(POINT_DEL_BUTTON,TRUE);
point_ops_button_set_sensitive(POINT_NEW_BUTTON,TRUE);
point_ops_button_set_sensitive(POINT_EDIT_BUTTON,TRUE);
point_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,TRUE);
}
/* update the clist to reflect this images bz list */
@ -870,6 +975,7 @@ paths_dialog_update (GimpImage* gimage)
/* g_slist_foreach(plist,paths_update_paths,NULL); */
/* select last one */
gtk_signal_handler_block(GTK_OBJECT(paths_dialog->paths_list),paths_dialog->selsigid);
gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list),
paths_dialog->current_path_list->last_selected_row,
@ -1094,11 +1200,11 @@ paths_dialog_delete_path_callback (GtkWidget * widget, gpointer udata)
paths_ops_button_set_sensitive(DUP_PATH_BUTTON,new_sz);
paths_ops_button_set_sensitive(DEL_PATH_BUTTON,new_sz);
paths_ops_button_set_sensitive(STROKE_PATH_BUTTON,new_sz);
paths_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,new_sz);
point_ops_button_set_sensitive(POINT_ADD_BUTTON,new_sz);
point_ops_button_set_sensitive(POINT_DEL_BUTTON,new_sz);
point_ops_button_set_sensitive(POINT_NEW_BUTTON,new_sz);
point_ops_button_set_sensitive(POINT_EDIT_BUTTON,new_sz);
point_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,new_sz);
}
static void
@ -1208,7 +1314,7 @@ paths_dialog_map_callback (GtkWidget *w,
{
if (!paths_dialog)
return;
gtk_window_add_accel_group (GTK_WINDOW (gtk_widget_get_toplevel(paths_dialog->paths_list)),
paths_dialog->accel_group);
@ -1325,7 +1431,8 @@ static gboolean
paths_replaced_current(PATHIMAGELISTP plp,BezierSelect *bezier_sel)
{
/* Is there a currently selected path in this image? */
if(paths_dialog && plp &&
/* ALT if(paths_dialog && plp && */
if(plp &&
plp->last_selected_row >= 0)
{
paths_update_bzpath(plp,bezier_sel);
@ -1408,7 +1515,9 @@ paths_update_preview(BezierSelect *bezier_sel)
/* update .. */
bezier_draw_curve (bezier_sel,paths_draw_segment_points,IMAGE_COORDS);
/* update the pixmap */
gtk_clist_set_pixtext(GTK_CLIST(paths_dialog->paths_list),
row,
0,
@ -1464,10 +1573,11 @@ paths_first_button_press(BezierSelect *bezier_sel,GDisplay * gdisp)
BZPATHP bzp;
PATHIMAGELISTP plp;
if(!paths_dialog)
return;
paths_dialog->been_selected = FALSE;
if(paths_dialog)
{
paths_dialog->been_selected = FALSE;
/*ALT return;*/
}
/* Button not pressed in this image...
* find which one it was pressed in if any.
@ -1482,7 +1592,7 @@ paths_first_button_press(BezierSelect *bezier_sel,GDisplay * gdisp)
bzp = paths_dialog_new_path(&plp,bzpoints_create(bezier_sel),gdisp->gimage,-1);
bzp->closed = bezier_sel->closed;
bzp->state = bezier_sel->state;
if(paths_dialog->gimage == gdisp->gimage)
if(paths_dialog && paths_dialog->gimage == gdisp->gimage)
{
paths_dialog->current_path_list = plp;
paths_add_path(bzp,-1);
@ -1501,11 +1611,11 @@ paths_newpoint_current(BezierSelect *bezier_sel,GDisplay * gdisp)
paths_ops_button_set_sensitive(DUP_PATH_BUTTON,TRUE);
paths_ops_button_set_sensitive(DEL_PATH_BUTTON,TRUE);
paths_ops_button_set_sensitive(STROKE_PATH_BUTTON,TRUE);
paths_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,TRUE);
point_ops_button_set_sensitive(POINT_NEW_BUTTON,TRUE);
point_ops_button_set_sensitive(POINT_DEL_BUTTON,TRUE);
point_ops_button_set_sensitive(POINT_ADD_BUTTON,TRUE);
point_ops_button_set_sensitive(POINT_EDIT_BUTTON,TRUE);
point_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,TRUE);
paths_update_preview(bezier_sel);
}
@ -1581,3 +1691,217 @@ pathsList_new(GimpImage * gimage,
return (PathsList *)pip;
}
/**************************************************************/
/* Code to save/load from filesystem */
/**************************************************************/
static GtkWidget *file_dlg = 0;
static int load_store;
static void path_write_current_to_file(FILE *f,BZPATHP bzp)
{
GSList *list = bzp->bezier_details;
BZPOINTP pdata;
fprintf(f, "Name: %s\n", bzp->name->str);
fprintf(f, "#POINTS: %d\n", g_slist_length(bzp->bezier_details));
fprintf(f, "CLOSED: %d\n", bzp->closed==1?1:0);
fprintf(f, "DRAW: %d\n", 0);
fprintf(f, "STATE: %d\n", bzp->state);
while(list)
{
pdata = (BZPOINTP)list->data;
fprintf(f,"TYPE: %d X: %d Y: %d\n", pdata->type, pdata->x, pdata->y);
list = g_slist_next(list);
}
}
static void file_ok_callback(GtkWidget * widget, gpointer client_data)
{
GtkFileSelection *fs;
FILE *f;
char* filename;
BZPATHP bzpath;
GSList * pts_list = NULL;
PATHIMAGELISTP plp;
gint row = paths_dialog->selected_row_num;
fs = GTK_FILE_SELECTION (file_dlg);
filename = gtk_file_selection_get_filename (fs);
if (load_store)
{
f = fopen(filename, "rb");
while(!feof(f))
{
gchar *txt = g_new(gchar,512);
gchar *txtstart = txt;
gint readfields = 0;
int val, x, y, type, closed, i, draw, state;
if(!fgets(txt,512,f) || strlen(txt) < 7)
{
g_warning("Failed to read from %s",filename);
gtk_widget_hide (file_dlg);
return;
}
txt += 6; /* Miss out 'Name: ' bit */
txt[strlen(txt)-1] = '\0';
readfields += fscanf(f, "#POINTS: %d\n", &val);
readfields += fscanf(f, "CLOSED: %d\n", &closed);
readfields += fscanf(f, "DRAW: %d\n", &draw);
readfields += fscanf(f, "STATE: %d\n", &state);
if(readfields != 4)
{
g_warning("Failed to read path from %s",filename);
gtk_widget_hide (file_dlg);
return;
}
for(i=0; i< val; i++)
{
BZPOINTP bpt;
readfields = fscanf(f,"TYPE: %d X: %d Y: %d\n", &type, &x, &y);
if(readfields != 3)
{
g_warning("Failed to read path points from %s",filename);
gtk_widget_hide (file_dlg);
return;
}
bpt = bzpoint_new(type, x, y);
pts_list = g_slist_append(pts_list,bpt);
}
bzpath = bzpath_new(pts_list,
closed,
state,
0, /* Can't be locked */
txt);
g_free(txtstart);
paths_dialog->current_path_list =
bzpath_add_to_current(paths_dialog->current_path_list,
bzpath,
paths_dialog->gimage,
row);
paths_add_path(bzpath,row);
gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list),
paths_dialog->current_path_list->last_selected_row,
0);
paths_ops_button_set_sensitive(DUP_PATH_BUTTON,val);
paths_ops_button_set_sensitive(DEL_PATH_BUTTON,val);
paths_ops_button_set_sensitive(STROKE_PATH_BUTTON,val);
paths_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,val);
point_ops_button_set_sensitive(POINT_ADD_BUTTON,val);
point_ops_button_set_sensitive(POINT_DEL_BUTTON,val);
point_ops_button_set_sensitive(POINT_NEW_BUTTON,val);
point_ops_button_set_sensitive(POINT_EDIT_BUTTON,val);
}
fclose(f);
}
else
{
BZPATHP bzp;
/* Get current selection... ignore if none */
if(paths_dialog->selected_row_num < 0)
return;
/* Get bzpath structure */
plp = paths_dialog->current_path_list;
bzp = (BZPATHP)g_slist_nth_data(plp->bz_paths,row);
f = fopen(filename, "wb");
if (NULL == f)
{
g_message (_("open failed on %s: %s\n"), filename, g_strerror(errno));
return;
}
/* Write the current selection out. */
path_write_current_to_file(f,bzp);
fclose(f);
}
gtk_widget_hide (file_dlg);
}
static void file_cancel_callback(GtkWidget * widget, gpointer data)
{
gtk_widget_hide (file_dlg);
}
static void make_file_dlg(gpointer data)
{
file_dlg = gtk_file_selection_new (_("Load/Store Bezier Curves"));
gtk_window_position (GTK_WINDOW (file_dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION (file_dlg)->cancel_button),
"clicked", (GtkSignalFunc) file_cancel_callback, data);
gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION (file_dlg)->ok_button),
"clicked", (GtkSignalFunc) file_ok_callback, data);
}
static void
path_load_callback()
{
if (!file_dlg)
{
make_file_dlg(NULL);
}
else
{
if (GTK_WIDGET_VISIBLE(file_dlg))
return;
}
gtk_window_set_title(GTK_WINDOW (file_dlg), _("Load Path"));
load_store = 1;
gtk_widget_show (file_dlg);
}
static void
path_store_callback()
{
if (!file_dlg)
{
make_file_dlg(NULL);
}
else
{
if (GTK_WIDGET_VISIBLE(file_dlg))
return;
}
gtk_window_set_title(GTK_WINDOW (file_dlg), _("Store Path"));
load_store = 0;
gtk_widget_show (file_dlg);
}
static void
paths_dialog_import_path_callback (GtkWidget * widget, gpointer udata)
{
/* Read and add at current position */
path_load_callback();
}
static void
paths_dialog_export_path_callback (GtkWidget * widget, gpointer udata)
{
/* Export the path to a file */
path_store_callback();
}

View File

@ -20,6 +20,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include "gdk/gdkkeysyms.h"
#include "appenv.h"
#include "draw_core.h"
@ -77,6 +79,10 @@ typedef struct {
int image_width, image_height;
int gimage_width, gimage_height;
/* pixmaps for the no preview bitmap */
GdkPixmap * pixmap_normal;
GdkPixmap * pixmap_selected;
/* state information */
gint selsigid;
GimpImage * gimage;
@ -118,7 +124,8 @@ static void paths_dialog_new_point_callback (GtkWidget *, gpointer);
static void paths_dialog_add_point_callback (GtkWidget *, gpointer);
static void paths_dialog_delete_point_callback (GtkWidget *, gpointer);
static void paths_dialog_edit_point_callback (GtkWidget *, gpointer);
static void paths_dialog_import_path_callback (GtkWidget *, gpointer);
static void paths_dialog_export_path_callback (GtkWidget *, gpointer);
#define NEW_PATH_BUTTON 1
#define DUP_PATH_BUTTON 2
@ -138,6 +145,10 @@ static MenuItem paths_ops[] =
paths_dialog_stroke_path_callback, NULL, NULL, NULL },
{ N_("Delete Path"), 'D', GDK_CONTROL_MASK,
paths_dialog_delete_path_callback, NULL, NULL, NULL },
{ N_("Import Path"), 'I', GDK_CONTROL_MASK,
paths_dialog_import_path_callback, NULL, NULL, NULL },
{ N_("Export Path"), 'E', GDK_CONTROL_MASK,
paths_dialog_export_path_callback, NULL, NULL, NULL },
{ NULL, 0, 0, NULL, NULL, NULL, NULL }
};
@ -317,11 +328,11 @@ GtkWidget * paths_dialog_create()
paths_ops_button_set_sensitive(DUP_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(DEL_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(STROKE_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_ADD_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_DEL_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_NEW_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_EDIT_BUTTON,FALSE);
point_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,FALSE);
}
return paths_dialog->vbox;
@ -332,6 +343,10 @@ static void paths_dialog_realized(GtkWidget *widget)
GdkColormap *colormap;
gchar dash_list[2]= {3,3};
/* Help out small displays */
if(preview_size < 64)
dash_list[1] = 1;
paths_dialog->gc = gdk_gc_new(widget->window);
gdk_gc_set_dashes(paths_dialog->gc,2,dash_list,2);
colormap = gtk_widget_get_colormap(paths_dialog->paths_list);
@ -384,15 +399,107 @@ bzpath_dialog_new(gint name_seed, gpointer udata)
return bzp;
}
/* Always return a copy that must be freed later */
static gchar *
strip_off_cnumber(gchar *str)
{
gchar * hashptr;
gint num;
gchar * copy;
if(!str)
return str;
copy = g_strdup(str);
if((hashptr = strrchr(copy,'#')) && /* have a hash */
strlen(hashptr) > 0 && /* followed by something */
(num = atoi(hashptr+1)) > 0 && /* which is a number */
((int)log10(num) + 1) == strlen(hashptr+1)) /* which is at the end */
{
gchar * tstr;
/* Has a #<number> */
*hashptr = '\0';
tstr = g_strdup(copy);
g_free(copy);
copy = tstr;
}
return copy;
}
/* Return NULL is already unique else a unique string */
static gchar *
unique_name(gchar *cstr)
{
GSList *tlist;
PATHIMAGELISTP plp;
gboolean unique = TRUE;
gchar *copy_cstr;
gchar *copy_test;
gchar *stripped_copy;
gint counter = 1;
/* Get bzpath structure */
plp = paths_dialog->current_path_list;
if(!plp)
return NULL;
tlist = plp->bz_paths;
while(tlist)
{
gchar *test_str = ((BZPATHP)(tlist->data))->name->str;
if(strcmp(cstr,test_str) == 0)
{
unique = FALSE;
break;
}
tlist = g_slist_next(tlist);
}
if(unique)
{
return NULL;
}
/* OK Clashes with something */
/* restart scan to find unique name */
stripped_copy = strip_off_cnumber(cstr);
copy_cstr = g_strdup_printf("%s#%d",stripped_copy,counter++);
tlist = plp->bz_paths;
while(tlist)
{
copy_test = ((BZPATHP)(tlist->data))->name->str;
if(strcmp(copy_cstr,copy_test) == 0)
{
g_free(copy_cstr);
copy_cstr = g_strdup_printf("%s#%d",stripped_copy,counter++);
tlist = plp->bz_paths;
continue;
}
tlist = g_slist_next(tlist);
}
g_free(stripped_copy);
return copy_cstr;
}
static BZPATHP
bzpath_copy(BZPATHP bzp)
{
BZPATHP bzp_copy = g_new0(BZPATH,1);
GString *s = g_string_new (NULL);
gchar *ext;
g_string_sprintf (s, "%s copy",bzp->name->str);
bzp_copy->name = s;
ext = unique_name(bzp->name->str);
bzp_copy->name = g_string_new(ext);
g_free(ext);
bzp_copy->closed = bzp->closed;
bzp_copy->state = bzp->state;
bzp_copy->bezier_details = bzpoints_copy(bzp->bezier_details);
@ -509,6 +616,8 @@ bz_change_name_row_to(gint row,gchar *text)
static void
paths_set_dash_line(GdkGC *gc,gboolean state)
{
gdk_gc_set_foreground(paths_dialog->gc, &paths_dialog->black);
if(state)
{
gdk_gc_set_line_attributes(gc,0,GDK_LINE_ON_OFF_DASH,GDK_CAP_BUTT,GDK_JOIN_ROUND);
@ -541,8 +650,6 @@ clear_pixmap_preview(PATHWIDGETP pwidget)
rgb_buf,
(paths_dialog->image_width + 4)*3);
gdk_gc_set_foreground(paths_dialog->gc, &paths_dialog->black);
paths_set_dash_line(paths_dialog->gc,FALSE);
gdk_draw_rectangle(pwidget->paths_pixmap,
@ -582,14 +689,26 @@ void paths_add_path(BZPATHP bzp,gint insrow)
}
else
{
pwidget->paths_pixmap =
gdk_pixmap_create_from_data (paths_dialog->vbox->window,
path_bits,
paths_dialog->image_width,
paths_dialog->image_height,
-1,
&paths_dialog->vbox->style->fg[GTK_STATE_SELECTED],
&paths_dialog->vbox->style->bg[GTK_STATE_SELECTED]);
if(!paths_dialog->pixmap_normal)
{
paths_dialog->pixmap_normal =
gdk_pixmap_create_from_data (paths_dialog->vbox->window,
path_bits,
paths_dialog->image_width,
paths_dialog->image_height,
-1,
&paths_dialog->vbox->style->fg[GTK_STATE_SELECTED],
&paths_dialog->vbox->style->bg[GTK_STATE_SELECTED]);
paths_dialog->pixmap_selected =
gdk_pixmap_create_from_data (paths_dialog->vbox->window,
path_bits,
paths_dialog->image_width,
paths_dialog->image_height,
-1,
&paths_dialog->vbox->style->fg[GTK_STATE_NORMAL],
&paths_dialog->vbox->style->bg[GTK_STATE_SELECTED]);
}
pwidget->paths_pixmap = paths_dialog->pixmap_normal;
}
gtk_clist_set_row_height(GTK_CLIST(paths_dialog->paths_list),
@ -737,20 +856,6 @@ paths_select_row(GtkWidget *widget,
bezier_paste_bezierselect_to_current(gdisp,bsel);
paths_update_preview(bsel);
beziersel_free(bsel);
/* Draw white as the border */
/* gdk_gc_set_foreground(paths_dialog->gc, &paths_dialog->black); */
/* gdk_draw_rectangle(pwidget->paths_pixmap, */
/* paths_dialog->gc, FALSE, 0, 0, */
/* paths_dialog->image_width+3, */
/* paths_dialog->image_height+3); */
/* gdk_draw_rectangle(pwidget->paths_pixmap, */
/* paths_dialog->gc, FALSE, 1, 1, */
/* paths_dialog->image_width+1, */
/* paths_dialog->image_height+1); */
}
static void
@ -766,19 +871,6 @@ paths_unselect_row(GtkWidget *widget,
if(!pwidget)
return;
/* gdk_gc_set_foreground(paths_dialog->gc, &paths_dialog->white); */
/* gdk_draw_rectangle(pwidget->paths_pixmap, */
/* paths_dialog->gc, FALSE, 0, 0, */
/* paths_dialog->image_width+3, */
/* paths_dialog->image_height+3); */
/* gdk_draw_rectangle(pwidget->paths_pixmap, */
/* paths_dialog->gc, FALSE, 1, 1, */
/* paths_dialog->image_width+1, */
/* paths_dialog->image_height+1); */
}
void
@ -796,6 +888,19 @@ paths_dialog_update (GimpImage* gimage)
* under our feet.
*/
if(!gimp_image_get_paths(gimage))
{
/* No paths is this layer */
paths_ops_button_set_sensitive(DUP_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(DEL_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(STROKE_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_ADD_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_DEL_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_NEW_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_EDIT_BUTTON,FALSE);
}
if (paths_dialog->gimage == gimage &&
paths_dialog->current_path_list == (PATHIMAGELISTP)gimp_image_get_paths(gimage))
return;
@ -827,11 +932,11 @@ paths_dialog_update (GimpImage* gimage)
paths_ops_button_set_sensitive(DUP_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(DEL_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(STROKE_PATH_BUTTON,FALSE);
paths_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_ADD_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_DEL_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_NEW_BUTTON,FALSE);
point_ops_button_set_sensitive(POINT_EDIT_BUTTON,FALSE);
point_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,FALSE);
return;
}
else
@ -839,11 +944,11 @@ paths_dialog_update (GimpImage* gimage)
paths_ops_button_set_sensitive(DUP_PATH_BUTTON,TRUE);
paths_ops_button_set_sensitive(DEL_PATH_BUTTON,TRUE);
paths_ops_button_set_sensitive(STROKE_PATH_BUTTON,TRUE);
paths_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,TRUE);
point_ops_button_set_sensitive(POINT_ADD_BUTTON,TRUE);
point_ops_button_set_sensitive(POINT_DEL_BUTTON,TRUE);
point_ops_button_set_sensitive(POINT_NEW_BUTTON,TRUE);
point_ops_button_set_sensitive(POINT_EDIT_BUTTON,TRUE);
point_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,TRUE);
}
/* update the clist to reflect this images bz list */
@ -870,6 +975,7 @@ paths_dialog_update (GimpImage* gimage)
/* g_slist_foreach(plist,paths_update_paths,NULL); */
/* select last one */
gtk_signal_handler_block(GTK_OBJECT(paths_dialog->paths_list),paths_dialog->selsigid);
gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list),
paths_dialog->current_path_list->last_selected_row,
@ -1094,11 +1200,11 @@ paths_dialog_delete_path_callback (GtkWidget * widget, gpointer udata)
paths_ops_button_set_sensitive(DUP_PATH_BUTTON,new_sz);
paths_ops_button_set_sensitive(DEL_PATH_BUTTON,new_sz);
paths_ops_button_set_sensitive(STROKE_PATH_BUTTON,new_sz);
paths_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,new_sz);
point_ops_button_set_sensitive(POINT_ADD_BUTTON,new_sz);
point_ops_button_set_sensitive(POINT_DEL_BUTTON,new_sz);
point_ops_button_set_sensitive(POINT_NEW_BUTTON,new_sz);
point_ops_button_set_sensitive(POINT_EDIT_BUTTON,new_sz);
point_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,new_sz);
}
static void
@ -1208,7 +1314,7 @@ paths_dialog_map_callback (GtkWidget *w,
{
if (!paths_dialog)
return;
gtk_window_add_accel_group (GTK_WINDOW (gtk_widget_get_toplevel(paths_dialog->paths_list)),
paths_dialog->accel_group);
@ -1325,7 +1431,8 @@ static gboolean
paths_replaced_current(PATHIMAGELISTP plp,BezierSelect *bezier_sel)
{
/* Is there a currently selected path in this image? */
if(paths_dialog && plp &&
/* ALT if(paths_dialog && plp && */
if(plp &&
plp->last_selected_row >= 0)
{
paths_update_bzpath(plp,bezier_sel);
@ -1408,7 +1515,9 @@ paths_update_preview(BezierSelect *bezier_sel)
/* update .. */
bezier_draw_curve (bezier_sel,paths_draw_segment_points,IMAGE_COORDS);
/* update the pixmap */
gtk_clist_set_pixtext(GTK_CLIST(paths_dialog->paths_list),
row,
0,
@ -1464,10 +1573,11 @@ paths_first_button_press(BezierSelect *bezier_sel,GDisplay * gdisp)
BZPATHP bzp;
PATHIMAGELISTP plp;
if(!paths_dialog)
return;
paths_dialog->been_selected = FALSE;
if(paths_dialog)
{
paths_dialog->been_selected = FALSE;
/*ALT return;*/
}
/* Button not pressed in this image...
* find which one it was pressed in if any.
@ -1482,7 +1592,7 @@ paths_first_button_press(BezierSelect *bezier_sel,GDisplay * gdisp)
bzp = paths_dialog_new_path(&plp,bzpoints_create(bezier_sel),gdisp->gimage,-1);
bzp->closed = bezier_sel->closed;
bzp->state = bezier_sel->state;
if(paths_dialog->gimage == gdisp->gimage)
if(paths_dialog && paths_dialog->gimage == gdisp->gimage)
{
paths_dialog->current_path_list = plp;
paths_add_path(bzp,-1);
@ -1501,11 +1611,11 @@ paths_newpoint_current(BezierSelect *bezier_sel,GDisplay * gdisp)
paths_ops_button_set_sensitive(DUP_PATH_BUTTON,TRUE);
paths_ops_button_set_sensitive(DEL_PATH_BUTTON,TRUE);
paths_ops_button_set_sensitive(STROKE_PATH_BUTTON,TRUE);
paths_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,TRUE);
point_ops_button_set_sensitive(POINT_NEW_BUTTON,TRUE);
point_ops_button_set_sensitive(POINT_DEL_BUTTON,TRUE);
point_ops_button_set_sensitive(POINT_ADD_BUTTON,TRUE);
point_ops_button_set_sensitive(POINT_EDIT_BUTTON,TRUE);
point_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,TRUE);
paths_update_preview(bezier_sel);
}
@ -1581,3 +1691,217 @@ pathsList_new(GimpImage * gimage,
return (PathsList *)pip;
}
/**************************************************************/
/* Code to save/load from filesystem */
/**************************************************************/
static GtkWidget *file_dlg = 0;
static int load_store;
static void path_write_current_to_file(FILE *f,BZPATHP bzp)
{
GSList *list = bzp->bezier_details;
BZPOINTP pdata;
fprintf(f, "Name: %s\n", bzp->name->str);
fprintf(f, "#POINTS: %d\n", g_slist_length(bzp->bezier_details));
fprintf(f, "CLOSED: %d\n", bzp->closed==1?1:0);
fprintf(f, "DRAW: %d\n", 0);
fprintf(f, "STATE: %d\n", bzp->state);
while(list)
{
pdata = (BZPOINTP)list->data;
fprintf(f,"TYPE: %d X: %d Y: %d\n", pdata->type, pdata->x, pdata->y);
list = g_slist_next(list);
}
}
static void file_ok_callback(GtkWidget * widget, gpointer client_data)
{
GtkFileSelection *fs;
FILE *f;
char* filename;
BZPATHP bzpath;
GSList * pts_list = NULL;
PATHIMAGELISTP plp;
gint row = paths_dialog->selected_row_num;
fs = GTK_FILE_SELECTION (file_dlg);
filename = gtk_file_selection_get_filename (fs);
if (load_store)
{
f = fopen(filename, "rb");
while(!feof(f))
{
gchar *txt = g_new(gchar,512);
gchar *txtstart = txt;
gint readfields = 0;
int val, x, y, type, closed, i, draw, state;
if(!fgets(txt,512,f) || strlen(txt) < 7)
{
g_warning("Failed to read from %s",filename);
gtk_widget_hide (file_dlg);
return;
}
txt += 6; /* Miss out 'Name: ' bit */
txt[strlen(txt)-1] = '\0';
readfields += fscanf(f, "#POINTS: %d\n", &val);
readfields += fscanf(f, "CLOSED: %d\n", &closed);
readfields += fscanf(f, "DRAW: %d\n", &draw);
readfields += fscanf(f, "STATE: %d\n", &state);
if(readfields != 4)
{
g_warning("Failed to read path from %s",filename);
gtk_widget_hide (file_dlg);
return;
}
for(i=0; i< val; i++)
{
BZPOINTP bpt;
readfields = fscanf(f,"TYPE: %d X: %d Y: %d\n", &type, &x, &y);
if(readfields != 3)
{
g_warning("Failed to read path points from %s",filename);
gtk_widget_hide (file_dlg);
return;
}
bpt = bzpoint_new(type, x, y);
pts_list = g_slist_append(pts_list,bpt);
}
bzpath = bzpath_new(pts_list,
closed,
state,
0, /* Can't be locked */
txt);
g_free(txtstart);
paths_dialog->current_path_list =
bzpath_add_to_current(paths_dialog->current_path_list,
bzpath,
paths_dialog->gimage,
row);
paths_add_path(bzpath,row);
gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list),
paths_dialog->current_path_list->last_selected_row,
0);
paths_ops_button_set_sensitive(DUP_PATH_BUTTON,val);
paths_ops_button_set_sensitive(DEL_PATH_BUTTON,val);
paths_ops_button_set_sensitive(STROKE_PATH_BUTTON,val);
paths_ops_button_set_sensitive(PATH_TO_SEL_BUTTON,val);
point_ops_button_set_sensitive(POINT_ADD_BUTTON,val);
point_ops_button_set_sensitive(POINT_DEL_BUTTON,val);
point_ops_button_set_sensitive(POINT_NEW_BUTTON,val);
point_ops_button_set_sensitive(POINT_EDIT_BUTTON,val);
}
fclose(f);
}
else
{
BZPATHP bzp;
/* Get current selection... ignore if none */
if(paths_dialog->selected_row_num < 0)
return;
/* Get bzpath structure */
plp = paths_dialog->current_path_list;
bzp = (BZPATHP)g_slist_nth_data(plp->bz_paths,row);
f = fopen(filename, "wb");
if (NULL == f)
{
g_message (_("open failed on %s: %s\n"), filename, g_strerror(errno));
return;
}
/* Write the current selection out. */
path_write_current_to_file(f,bzp);
fclose(f);
}
gtk_widget_hide (file_dlg);
}
static void file_cancel_callback(GtkWidget * widget, gpointer data)
{
gtk_widget_hide (file_dlg);
}
static void make_file_dlg(gpointer data)
{
file_dlg = gtk_file_selection_new (_("Load/Store Bezier Curves"));
gtk_window_position (GTK_WINDOW (file_dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION (file_dlg)->cancel_button),
"clicked", (GtkSignalFunc) file_cancel_callback, data);
gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION (file_dlg)->ok_button),
"clicked", (GtkSignalFunc) file_ok_callback, data);
}
static void
path_load_callback()
{
if (!file_dlg)
{
make_file_dlg(NULL);
}
else
{
if (GTK_WIDGET_VISIBLE(file_dlg))
return;
}
gtk_window_set_title(GTK_WINDOW (file_dlg), _("Load Path"));
load_store = 1;
gtk_widget_show (file_dlg);
}
static void
path_store_callback()
{
if (!file_dlg)
{
make_file_dlg(NULL);
}
else
{
if (GTK_WIDGET_VISIBLE(file_dlg))
return;
}
gtk_window_set_title(GTK_WINDOW (file_dlg), _("Store Path"));
load_store = 0;
gtk_widget_show (file_dlg);
}
static void
paths_dialog_import_path_callback (GtkWidget * widget, gpointer udata)
{
/* Read and add at current position */
path_load_callback();
}
static void
paths_dialog_export_path_callback (GtkWidget * widget, gpointer udata)
{
/* Export the path to a file */
path_store_callback();
}

View File

@ -108,6 +108,8 @@ static GSList * bezier_insert_in_list (GSList *, int);
static int test_add_point_on_segment (BezierSelect *, BezierPoint *, int, int, int, int, int);
static void bezier_to_sel_internal (BezierSelect *, Tool *, GDisplay *, gint, gint);
static void bezier_stack_points (BezierSelect *, GdkPoint *, int);
static gboolean stroke_interpolatable (int, int, int, int, gdouble);
static void bezier_stack_points_aux (GdkPoint *, int, int, gdouble);
static BezierMatrix basis =
{
@ -1710,197 +1712,6 @@ bezier_paste_bezierselect_to_current(GDisplay *gdisp,BezierSelect *bsel)
}
}
static GtkWidget *file_dlg = 0;
static int load_store;
FILE *f;
static void bezier_buffer_save_foreach(GtkWidget *w,
gpointer client_data)
{
PasteNamedDlg *pn_dlg;
BezierNamedBuffer * nb;
BezierPoint *pt;
int i;
pn_dlg = (PasteNamedDlg *) client_data;
nb = (BezierNamedBuffer *) gtk_object_get_user_data (GTK_OBJECT (w));
fprintf(f, "Name: %s\n", nb->name);
fprintf(f, "#POINTS: %d\n", nb->sel->num_points);
fprintf(f, "CLOSED: %d\n", nb->sel->closed==1?1:0);
fprintf(f, "DRAW: %d\n", nb->sel->draw);
fprintf(f, "STATE: %d\n", nb->sel->state);
pt = nb->sel->points;
for(i=0; i< nb->sel->num_points; i++)
{
fprintf(f,"TYPE: %d X: %d Y: %d\n", pt->type, pt->x, pt->y);
pt = pt->next;
}
}
static void file_ok_callback(GtkWidget * widget, gpointer client_data)
{
GtkFileSelection *fs;
char* filename;
fs = GTK_FILE_SELECTION (file_dlg);
filename = gtk_file_selection_get_filename (fs);
if (load_store)
{
PasteNamedDlg *pn_dlg;
BezierNamedBuffer * nb;
pn_dlg = (PasteNamedDlg *) client_data;
f = fopen(filename, "rb");
printf(_("reading %s\n"), filename);
while(!feof(f))
{
char txt[30];
int val, x, y, type, closed, i, draw, state;
/*
fscanf(f, "%s", txt);
if (strcmp("BEZIER_EXTENDS",txt))
{
GString *s;
fclose(f);
s = g_string_new (_("Open failed: "));
g_string_append (s, _("Bezier Load"));
g_message (s->str);
g_string_free (s, TRUE);
return;
}
*/
fscanf(f, "Name: %s\n", txt);
fscanf(f, "#POINTS: %d\n", &val);
fscanf(f, "CLOSED: %d\n", &closed);
fscanf(f, "DRAW: %d\n", &draw);
fscanf(f, "STATE: %d\n", &state);
nb = (BezierNamedBuffer *) g_malloc (sizeof(BezierNamedBuffer));
nb->name = g_strdup ((char *) txt);
nb->sel = (BezierSelect *) g_malloc( sizeof (BezierSelect));
if (nb->sel == NULL)
{
return;
}
nb->sel->closed = 0;
nb->sel->points = NULL; /* initially there are no points */
nb->sel->cur_anchor = NULL;
nb->sel->cur_control = NULL;
nb->sel->last_point = NULL;
nb->sel->num_points = 0; /* intially there are no points */
nb->sel->mask = NULL; /* empty mask */
nb->sel->scanlines = NULL;
for(i=0; i< val; i++)
{
fscanf(f,"TYPE: %d X: %d Y: %d\n", &type, &x, &y);
bezier_add_point( nb->sel, type, x, y);
}
if ( closed )
{
nb->sel->last_point->next = nb->sel->points;
nb->sel->points->prev = nb->sel->last_point;
nb->sel->cur_anchor = nb->sel->points;
nb->sel->cur_control = nb->sel-> points->next;
nb->sel->closed = 1;
}
nb->sel->state = state;
nb->sel->draw = draw;
bezier_named_buffers = g_slist_append (bezier_named_buffers, (void *) nb);
}
fclose(f);
}
else
{
PasteNamedDlg *pn_dlg;
f = fopen(filename, "wb");
if (NULL == f)
{
perror(filename);
return;
}
pn_dlg = (PasteNamedDlg *) client_data;
/*
fprintf(f,"BEZIER_EXTENDS\n");
*/
gtk_container_foreach ((GtkContainer*) pn_dlg->list,
bezier_buffer_save_foreach,
client_data);
fclose(f);
}
gtk_widget_hide (file_dlg);
}
static void file_cancel_callback(GtkWidget * widget, gpointer data)
{
gtk_widget_hide (file_dlg);
}
static void make_file_dlg(gpointer data)
{
file_dlg = gtk_file_selection_new (_("Load/Store Bezier Curves"));
gtk_window_position (GTK_WINDOW (file_dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION (file_dlg)->cancel_button),
"clicked", (GtkSignalFunc) file_cancel_callback, data);
gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION (file_dlg)->ok_button),
"clicked", (GtkSignalFunc) file_ok_callback, data);
}
static void load_callback(GtkWidget * widget, gpointer data)
{
if (!file_dlg)
{
make_file_dlg(data);
}
else
{
if (GTK_WIDGET_VISIBLE(file_dlg))
return;
}
gtk_window_set_title(GTK_WINDOW (file_dlg), _("Load Bezier Curves"));
load_store = 1;
gtk_widget_show (file_dlg);
}
static void store_callback(GtkWidget * widget, gpointer data)
{
if (!file_dlg)
{
make_file_dlg(data);
}
else
{
if (GTK_WIDGET_VISIBLE(file_dlg))
return;
}
gtk_window_set_title(GTK_WINDOW (file_dlg), _("Store Bezier Curves"));
load_store = 0;
gtk_widget_show (file_dlg);
}
static void
bezier_to_sel_internal(BezierSelect *bezier_sel,
Tool *tool,
@ -2191,6 +2002,25 @@ void bezier_select_mode(gint mode)
ModeEdit = mode;
}
/* The curve has to be closed to do a selection. */
void
bezier_to_selection(BezierSelect *bezier_sel,
GDisplay *gdisp)
{
/* Call the internal function */
if(!bezier_sel->closed)
{
g_warning("Curve not closed");
return;
}
/* force the passed selection to be the current selection..*/
/* This loads it into curSel for this image */
bezier_paste_bezierselect_to_current(gdisp,bezier_sel);
bezier_to_sel_internal(curSel,curTool,gdisp,ADD,1);
}
void printSel( BezierSelect *sel)
{
BezierPoint *pt;
@ -2212,61 +2042,166 @@ void printSel( BezierSelect *sel)
printf("state: %d\n", sel->state);
}
static gdouble *stroke_points = NULL;
static gint num_stroke_points = 0;
static gdouble *stroke_points = NULL;
static gint num_stroke_points = 0; /* num of valid points */
static gint len_stroke_points = 0; /* allocated length */
/* check whether vectors (offx, offy), (l_offx, l_offy) have the same angle. */
static gboolean
stroke_interpolatable (int offx, int offy, int l_offx, int l_offy, gdouble error)
{
if ((offx == l_offx) & (offy == l_offy))
return TRUE;
else if ((offx == 0) | (l_offx == 0))
if (offx == l_offx)
return ((0 <= offy) & (0 <= offy)) | ((offy < 0) & (l_offy < 0));
else
return FALSE;
else if ((offy == 0) | (l_offy == 0))
if (offy == l_offy)
return ((0 < offx) & (0 < l_offx)) | ((offx < 0) & (l_offx < 0));
else
return FALSE;
/* At this point, we can assert: offx, offy, l_offx, l_offy != 0 */
else if (((0 < offx) & (0 < l_offx)) | ((offx < 0) & (l_offx < 0)))
{
gdouble grad1, grad2;
if (ABS (offy) < ABS (offx))
{
grad1 = (gdouble) offy / (gdouble) offx;
grad2 = (gdouble) l_offy / (gdouble) l_offx;
}
else
{
grad1 = (gdouble) offx / (gdouble) offy;
grad2 = (gdouble) l_offx / (gdouble) l_offy;
}
/* printf ("error: %f / %f\n", ABS (grad1 - grad2), error); */
return (ABS (grad1 - grad2) <= error);
}
else
return FALSE;
}
static void
bezier_stack_points_aux (GdkPoint *points,
int start,
int end,
gdouble error)
{
const gint expand_size = 32;
gint med;
gint offx, offy, l_offx, l_offy;
if (stroke_points == NULL)
return;
/* BASE CASE: stack the end point */
if (end - start <= 1)
{
if ((stroke_points[num_stroke_points * 2 - 2] == points[end].x)
&& (stroke_points[num_stroke_points * 2 - 1] == points[end].y))
return;
num_stroke_points++;
if (len_stroke_points <= num_stroke_points)
{
len_stroke_points += expand_size;
stroke_points = g_renew (double, stroke_points, 2 * len_stroke_points);
if (stroke_points == NULL)
{
len_stroke_points = num_stroke_points = 0;
return;
}
}
stroke_points[num_stroke_points * 2 - 2] = points[end].x;
stroke_points[num_stroke_points * 2 - 1] = points[end].y;
return;
}
if (end - start <= 32)
{
gint i;
for (i = start+ 1; i <= end; i++)
bezier_stack_points_aux (points, i, i, 0);
return;
}
/* Otherwise, check whether to divide the segment recursively */
offx = points[end].x - points[start].x;
offy = points[end].y - points[start].y;
med = (end + start) / 2;
l_offx = points[med].x - points[start].x;
l_offy = points[med].y - points[start].y;
if (! stroke_interpolatable (offx, offy, l_offx, l_offy, error))
{
bezier_stack_points_aux (points, start, med, error);
bezier_stack_points_aux (points, med, end, error);
return;
}
l_offx = points[end].x - points[med].x;
l_offy = points[end].y - points[med].y;
if (! stroke_interpolatable (offx, offy, l_offx, l_offy, error))
{
bezier_stack_points_aux (points, start, med, error);
bezier_stack_points_aux (points, med, end, error);
return;
}
/* Now, the curve can be represented by a points pair: (start, end).
So, add the last point to stroke_points. */
bezier_stack_points_aux (points, end, end, 0);
}
static void
bezier_stack_points (BezierSelect *bezier_sel,
GdkPoint *points,
int npoints)
{
int i, j;
gint i;
gint expand_size = 32;
gint minx, maxx, miny, maxy;
gdouble error;
if (stroke_points == NULL)
if (npoints < 2) /* Does this happen? */
return;
if (stroke_points == NULL) /* initialize it here */
{
j = 0;
num_stroke_points = npoints / 2;
stroke_points = g_new (double, 2 * num_stroke_points );
}
else
{
j = num_stroke_points * 2;
num_stroke_points += npoints / 2;
stroke_points = g_renew (double, stroke_points, 2 * num_stroke_points);
num_stroke_points = 0;
len_stroke_points = expand_size;
stroke_points = g_new (double, 2 * len_stroke_points);
}
/* copy points into stroke_points SPARSELY */
for (i = 0; i < npoints / 2 - 1; i++)
maxx = minx = points[0].x;
maxy = miny = points[0].y;
for (i = 1; i < npoints; i++)
{
stroke_points[j++] = points[i * 2].x;
stroke_points[j++] = points[i * 2].y;
if (points[i].x < minx)
minx = points[i].x;
else if (maxx < points[i].x)
maxx = points[i].x;
if (points[i].y < miny)
miny = points[i].x;
else if (maxy < points[i].y)
maxy = points[i].y;
}
/* the last point should be included anyway */
stroke_points[num_stroke_points * 2 - 2] = points[npoints - 1].x;
stroke_points[num_stroke_points * 2 - 1] = points[npoints - 1].y;
/* allow one pixel fluctuation */
error = 2.0 / MAX(maxx - minx, maxy - miny);
/* add the start point */
bezier_stack_points_aux (points, 0, 0, 0);
/* divide segments recursively */
bezier_stack_points_aux (points, 0, npoints - 1, error);
/* printf ("npoints: %d\n", npoints); */
}
/* The curve has to be closed to do a selection. */
void
bezier_to_selection(BezierSelect *bezier_sel,
GDisplay *gdisp)
{
/* Call the internal function */
if(!bezier_sel->closed)
{
g_warning("Curve not closed");
return;
}
/* force the passed selection to be the current selection..*/
/* This loads it into curSel for this image */
bezier_paste_bezierselect_to_current(gdisp,bezier_sel);
bezier_to_sel_internal(curSel,curTool,gdisp,ADD,1);
}
void
bezier_stroke (BezierSelect *bezier_sel,
GDisplay *gdisp,
@ -2277,6 +2212,7 @@ bezier_stroke (BezierSelect *bezier_sel,
int num_points;
Argument *return_vals;
int nreturn_vals;
int redraw = FALSE;
/* stack points */
points = bezier_sel->points;
@ -2301,8 +2237,10 @@ bezier_stroke (BezierSelect *bezier_sel,
else
{
if (bezier_sel->closed)
num_points--;
{
redraw = TRUE;
num_points--;
}
while (num_points >= 4)
{
bezier_draw_segment (bezier_sel, points,
@ -2316,18 +2254,33 @@ bezier_stroke (BezierSelect *bezier_sel,
}
}
return_vals = procedural_db_run_proc ("gimp_paintbrush",
&nreturn_vals,
PDB_DRAWABLE, drawable_ID (gimage_active_drawable (gdisp->gimage)),
PDB_FLOAT, (gdouble) 0,
PDB_INT32, (gint32) num_stroke_points * 2,
PDB_FLOATARRAY, stroke_points,
PDB_END);
if (stroke_points)
{
return_vals = procedural_db_run_proc ("gimp_paintbrush",
&nreturn_vals,
PDB_DRAWABLE, drawable_ID (gimage_active_drawable (gdisp->gimage)),
PDB_FLOAT, (gdouble) 0,
PDB_INT32, (gint32) num_stroke_points * 2,
PDB_FLOATARRAY, stroke_points,
PDB_END);
if (return_vals[0].value.pdb_int == PDB_SUCCESS)
{
if (redraw)
{
/* FIXME: how to update the image? */
}
gdisplays_flush ();
}
else
g_message (_("Paintbrush operation failed."));
procedural_db_destroy_args (return_vals, nreturn_vals);
g_free (stroke_points);
}
/* printf ("num_stroke_points: %d\ndone.\n", num_stroke_points); */
g_free (stroke_points);
stroke_points = NULL;
num_stroke_points = 0;
gdisplays_flush ();
return;
len_stroke_points = num_stroke_points = 0;
}

View File

@ -25,7 +25,6 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <regex.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"

View File

@ -25,7 +25,6 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <regex.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"

View File

@ -25,7 +25,6 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <regex.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"

View File

@ -25,7 +25,6 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <regex.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"