From 67dbf49bf25b74b37bc17d5708c4425c4fe8b626 Mon Sep 17 00:00:00 2001 From: BST 1999 Andy Thomas Date: Mon, 5 Apr 1999 23:33:50 +0000 Subject: [PATCH] Changed:- Mon Apr 5 22:24:30 BST 1999 Andy Thomas Changed:- * app/bezier_select.c * app/bezier_selectP.h * app/paths_cmds.c * app/pathsP.h * app/paths_dialog.c * app/xcf.c * tools/pdbgen/pdb/paths.pdb New PDB functions. gimp_path_get_point_at_dist (gets the x,y of a point a given distance along the curve & the normal at the point). gimp_path_get_tattoo gimp_get_path_by_tattoo Paths now have tattoos (similar to the layer and image tattoos). * app/move.c * app/scroll.c Try to fix the problem where mouse events from the rulers get mixed up with those from the canvas causing guides & image dragging to "jump" around when the mouse enters the ruler areas. --- ChangeLog | 28 ++ app/bezier_select.c | 380 +++++++++++++++++++++----- app/bezier_selectP.h | 6 +- app/display/gimpdisplay-scroll.c | 5 + app/display/gimpdisplayshell-scroll.c | 5 + app/gui/paths-dialog.c | 120 ++++++-- app/move.c | 6 + app/pathsP.h | 6 +- app/paths_cmds.c | 281 +++++++++++++++++++ app/paths_dialog.c | 120 ++++++-- app/scroll.c | 5 + app/tools/bezier_select.c | 380 +++++++++++++++++++++----- app/tools/bezier_selectP.h | 6 +- app/tools/gimpmovetool.c | 6 + app/tools/move.c | 6 + app/xcf.c | 23 +- app/xcf/xcf.c | 23 +- tools/pdbgen/pdb/paths.pdb | 174 +++++++++++- 18 files changed, 1376 insertions(+), 204 deletions(-) diff --git a/ChangeLog b/ChangeLog index d01c489e23..248945abad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +Mon Apr 5 23:24:30 BST 1999 Andy Thomas + + Changed:- + + * app/bezier_select.c + * app/bezier_selectP.h + * app/paths_cmds.c + * app/pathsP.h + * app/paths_dialog.c + * app/xcf.c + * tools/pdbgen/pdb/paths.pdb + + New PDB functions. + gimp_path_get_point_at_dist (gets the x,y of a point a given distance + along the curve & the normal at the point). + gimp_path_get_tattoo + gimp_get_path_by_tattoo + + + Paths now have tattoos (similar to the layer and image tattoos). + + * app/move.c + * app/scroll.c + + Try to fix the problem where mouse events from the rulers get + mixed up with those from the canvas causing guides & image dragging + to "jump" around when the mouse enters the ruler areas. + Mon Apr 5 23:59:37 MEST 1999 Sven Neumann * app/color_balance.c: Color-balance didn't work when used diff --git a/app/bezier_select.c b/app/bezier_select.c index 85a58ff5b4..9863ef7002 100644 --- a/app/bezier_select.c +++ b/app/bezier_select.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "appenv.h" #include "draw_core.h" #include "edit_selection.h" @@ -61,6 +62,8 @@ #define NO 0 #define YES 1 +#define ROUND(x) ((int) ((x) + 0.5)) + /* bezier select type definitions */ typedef double BezierMatrix[4][4]; @@ -84,6 +87,24 @@ struct _named_buffer char * name; }; +typedef struct { + gdouble *stroke_points; + gint num_stroke_points; /* num of valid points */ + gint len_stroke_points; /* allocated length */ +} BezierRenderPnts; + +typedef struct { + gboolean firstpnt; + gdouble curdist; + gdouble dist; + gdouble *gradient; + gint *x; + gint *y; + gdouble lastx; + gdouble lasty; + gboolean found; +} BezierDistance; + static void bezier_select_button_press (Tool *, GdkEventButton *, gpointer); static void bezier_select_button_release (Tool *, GdkEventButton *, gpointer); static void bezier_select_motion (Tool *, GdkEventMotion *, gpointer); @@ -96,20 +117,20 @@ static void bezier_draw_handles (BezierSelect *); static void bezier_draw_current (BezierSelect *); static void bezier_draw_point (BezierSelect *, BezierPoint *, int); static void bezier_draw_line (BezierSelect *, BezierPoint *, BezierPoint *); -static void bezier_draw_segment (BezierSelect *, BezierPoint *, int, int, BezierPointsFunc); -static void bezier_draw_segment_points (BezierSelect *, GdkPoint *, int); +static void bezier_draw_segment (BezierSelect *, BezierPoint *, int, int, BezierPointsFunc,gpointer); +static void bezier_draw_segment_points (BezierSelect *, GdkPoint *, int, gpointer); static void bezier_compose (BezierMatrix, BezierMatrix, BezierMatrix); static void bezier_convert (BezierSelect *, GDisplay *, int, int); -static void bezier_convert_points (BezierSelect *, GdkPoint *, int); +static void bezier_convert_points (BezierSelect *, GdkPoint *, int, gpointer); static void bezier_convert_line (GSList **, int, int, int, int); 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 void bezier_stack_points (BezierSelect *, GdkPoint *, int, gpointer); static gboolean stroke_interpolatable (int, int, int, int, gdouble); -static void bezier_stack_points_aux (GdkPoint *, int, int, gdouble); +static void bezier_stack_points_aux (GdkPoint *, int, int, gdouble, BezierRenderPnts *); static BezierMatrix basis = { @@ -233,7 +254,10 @@ bezier_select_load (void *gdisp_ptr, } void -bezier_draw_curve (BezierSelect *bezier_sel,BezierPointsFunc func, gint coord) +bezier_draw_curve (BezierSelect *bezier_sel, + BezierPointsFunc func, + gint coord, + gpointer udata) { BezierPoint * points; BezierPoint * start_pt; @@ -248,7 +272,8 @@ bezier_draw_curve (BezierSelect *bezier_sel,BezierPointsFunc func, gint coord) do { bezier_draw_segment (bezier_sel, points, SUBDIVIDE, coord, - func); + func, + udata); points = points->next; points = points->next; @@ -263,7 +288,8 @@ bezier_draw_curve (BezierSelect *bezier_sel,BezierPointsFunc func, gint coord) { bezier_draw_segment (bezier_sel, points, SUBDIVIDE, coord, - func); + func, + udata); points = points->next; points = points->next; @@ -447,7 +473,7 @@ bezier_add_point_on_segment(int x, if (test_add_point_on_segment (bezier_sel, points, SUBDIVIDE, - SCREEN_COORDS, + IMAGE_COORDS, x, y, halfwidth)) { @@ -953,7 +979,7 @@ bezier_select_draw (Tool *tool) } if (draw_curve) - bezier_draw_curve (bezier_sel,bezier_draw_segment_points,SCREEN_COORDS); + bezier_draw_curve (bezier_sel,bezier_draw_segment_points,SCREEN_COORDS,NULL); if (draw_handles) bezier_draw_handles (bezier_sel); if (draw_current) @@ -1082,7 +1108,8 @@ bezier_draw_current (BezierSelect *bezier_sel) if (points) bezier_draw_segment (bezier_sel, points, SUBDIVIDE, SCREEN_COORDS, - bezier_draw_segment_points); + bezier_draw_segment_points, + NULL); if (points != bezier_sel->cur_anchor) { @@ -1095,7 +1122,8 @@ bezier_draw_current (BezierSelect *bezier_sel) if (points) bezier_draw_segment (bezier_sel, bezier_sel->cur_anchor, SUBDIVIDE, SCREEN_COORDS, - bezier_draw_segment_points); + bezier_draw_segment_points, + NULL); } } @@ -1158,7 +1186,8 @@ bezier_draw_segment (BezierSelect *bezier_sel, BezierPoint *points, int subdivisions, int space, - BezierPointsFunc points_func) + BezierPointsFunc points_func, + gpointer udata) { #define ROUND(x) ((int) ((x) + 0.5)) @@ -1275,7 +1304,7 @@ bezier_draw_segment (BezierSelect *bezier_sel, /* if the point buffer is full put it to the screen and zero it out */ if (index >= npoints) { - (* points_func) (bezier_sel, gdk_points, index); + (* points_func) (bezier_sel, gdk_points, index, udata); index = 0; } } @@ -1286,13 +1315,14 @@ bezier_draw_segment (BezierSelect *bezier_sel, /* if there are points in the buffer, then put them on the screen */ if (index) - (* points_func) (bezier_sel, gdk_points, index); + (* points_func) (bezier_sel, gdk_points, index, udata); } static void bezier_draw_segment_points (BezierSelect *bezier_sel, GdkPoint *points, - int npoints) + int npoints, + gpointer udata) { gdk_draw_points (bezier_sel->core->win, bezier_sel->core->gc, points, npoints); @@ -1388,7 +1418,8 @@ bezier_convert (BezierSelect *bezier_sel, do { bezier_draw_segment (bezier_sel, points, subdivisions, draw_type, - bezier_convert_points); + bezier_convert_points, + NULL); /* advance to the next segment */ points = points->next; @@ -1478,7 +1509,8 @@ bezier_convert (BezierSelect *bezier_sel, static void bezier_convert_points (BezierSelect *bezier_sel, GdkPoint *points, - int npoints) + int npoints, + gpointer udata) { int i; @@ -1765,8 +1797,6 @@ test_add_point_on_segment (BezierSelect *bezier_sel, int halfwidth) { -#define ROUND(x) ((int) ((x) + 0.5)) - BezierPoint *points; BezierMatrix geometry; BezierMatrix tmp1, tmp2; @@ -2042,10 +2072,6 @@ void printSel( BezierSelect *sel) printf("state: %d\n", sel->state); } -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) @@ -2088,35 +2114,36 @@ static void bezier_stack_points_aux (GdkPoint *points, int start, int end, - gdouble error) + gdouble error, + BezierRenderPnts *rpnts) { const gint expand_size = 32; gint med; gint offx, offy, l_offx, l_offy; - if (stroke_points == NULL) + if (rpnts->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)) + if ((rpnts->stroke_points[rpnts->num_stroke_points * 2 - 2] == points[end].x) + && (rpnts->stroke_points[rpnts->num_stroke_points * 2 - 1] == points[end].y)) return; - num_stroke_points++; - if (len_stroke_points <= num_stroke_points) + rpnts->num_stroke_points++; + if (rpnts->len_stroke_points <= rpnts->num_stroke_points) { - len_stroke_points += expand_size; - stroke_points = g_renew (double, stroke_points, 2 * len_stroke_points); - if (stroke_points == NULL) + rpnts->len_stroke_points += expand_size; + rpnts->stroke_points = g_renew (double, rpnts->stroke_points, 2 * rpnts->len_stroke_points); + if (rpnts->stroke_points == NULL) { - len_stroke_points = num_stroke_points = 0; + rpnts->len_stroke_points = rpnts->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; + rpnts->stroke_points[rpnts->num_stroke_points * 2 - 2] = points[end].x; + rpnts->stroke_points[rpnts->num_stroke_points * 2 - 1] = points[end].y; return; } @@ -2125,7 +2152,7 @@ bezier_stack_points_aux (GdkPoint *points, gint i; for (i = start+ 1; i <= end; i++) - bezier_stack_points_aux (points, i, i, 0); + bezier_stack_points_aux (points, i, i, 0,rpnts); return; } /* Otherwise, check whether to divide the segment recursively */ @@ -2138,8 +2165,8 @@ bezier_stack_points_aux (GdkPoint *points, 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); + bezier_stack_points_aux (points, start, med, error, rpnts); + bezier_stack_points_aux (points, med, end, error, rpnts); return; } @@ -2148,33 +2175,35 @@ bezier_stack_points_aux (GdkPoint *points, 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); + bezier_stack_points_aux (points, start, med, error, rpnts); + bezier_stack_points_aux (points, med, end, error, rpnts); 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); + bezier_stack_points_aux (points, end, end, 0, rpnts); } static void bezier_stack_points (BezierSelect *bezier_sel, GdkPoint *points, - int npoints) + int npoints, + gpointer udata) { gint i; gint expand_size = 32; gint minx, maxx, miny, maxy; gdouble error; + BezierRenderPnts *rpnts = udata; if (npoints < 2) /* Does this happen? */ return; - if (stroke_points == NULL) /* initialize it here */ + if (rpnts->stroke_points == NULL) /* initialize it here */ { - num_stroke_points = 0; - len_stroke_points = expand_size; - stroke_points = g_new (double, 2 * len_stroke_points); + rpnts->num_stroke_points = 0; + rpnts->len_stroke_points = expand_size; + rpnts->stroke_points = g_new (double, 2 * rpnts->len_stroke_points); } maxx = minx = points[0].x; @@ -2194,41 +2223,39 @@ bezier_stack_points (BezierSelect *bezier_sel, error = 2.0 / MAX(maxx - minx, maxy - miny); /* add the start point */ - bezier_stack_points_aux (points, 0, 0, 0); + bezier_stack_points_aux (points, 0, 0, 0, rpnts); /* divide segments recursively */ - bezier_stack_points_aux (points, 0, npoints - 1, error); + bezier_stack_points_aux (points, 0, npoints - 1, error, rpnts); /* printf ("npoints: %d\n", npoints); */ } -void -bezier_stroke (BezierSelect *bezier_sel, - GDisplay *gdisp, - int subdivisions, - int open_path) +static gint +bezier_gen_points(BezierSelect *bezier_sel, + int open_path, + BezierRenderPnts *rpnts) { BezierPoint * points; int num_points; - Argument *return_vals; - int nreturn_vals; int redraw = FALSE; /* stack points */ points = bezier_sel->points; num_points = bezier_sel->num_points; - + if (bezier_sel->closed && (! open_path)) { BezierPoint * start_pt; - + start_pt = bezier_sel->points; - + do { bezier_draw_segment (bezier_sel, points, SUBDIVIDE, IMAGE_COORDS, - bezier_stack_points); - + bezier_stack_points, + (gpointer)rpnts); + points = points->next; points = points->next; points = points->next; @@ -2245,7 +2272,8 @@ bezier_stroke (BezierSelect *bezier_sel, { bezier_draw_segment (bezier_sel, points, SUBDIVIDE, IMAGE_COORDS, - bezier_stack_points); + bezier_stack_points, + (gpointer)rpnts); points = points->next; points = points->next; @@ -2254,7 +2282,23 @@ bezier_stroke (BezierSelect *bezier_sel, } } - if (stroke_points) + return (redraw); +} + +void +bezier_stroke (BezierSelect *bezier_sel, + GDisplay *gdisp, + int subdivisions, + int open_path) +{ + Argument *return_vals; + int nreturn_vals; + int redraw; + BezierRenderPnts *rpnts = g_new0(BezierRenderPnts,1); + + redraw = bezier_gen_points(bezier_sel,open_path,rpnts); + + if (rpnts->stroke_points) { GimpDrawable *drawable; int offset_x, offset_y; @@ -2266,8 +2310,8 @@ bezier_stroke (BezierSelect *bezier_sel, { gdouble *ptr; - ptr = stroke_points; - while (ptr < stroke_points + (num_stroke_points * 2)) + ptr = rpnts->stroke_points; + while (ptr < rpnts->stroke_points + (rpnts->num_stroke_points * 2)) { *ptr++ -= offset_x; *ptr++ -= offset_y; @@ -2278,8 +2322,8 @@ bezier_stroke (BezierSelect *bezier_sel, &nreturn_vals, PDB_DRAWABLE, drawable_ID (drawable), PDB_FLOAT, (gdouble) 0, - PDB_INT32, (gint32) num_stroke_points * 2, - PDB_FLOATARRAY, stroke_points, + PDB_INT32, (gint32) rpnts->num_stroke_points * 2, + PDB_FLOATARRAY, rpnts->stroke_points, PDB_END); if (return_vals[0].value.pdb_int == PDB_SUCCESS) @@ -2295,10 +2339,206 @@ bezier_stroke (BezierSelect *bezier_sel, procedural_db_destroy_args (return_vals, nreturn_vals); - g_free (stroke_points); + g_free (rpnts->stroke_points); } /* printf ("num_stroke_points: %d\ndone.\n", num_stroke_points); */ - stroke_points = NULL; - len_stroke_points = num_stroke_points = 0; + rpnts->stroke_points = NULL; + rpnts->len_stroke_points = rpnts->num_stroke_points = 0; + + g_free(rpnts); +} + +static void +bezier_draw_segment_for_distance (BezierSelect *bezier_sel, + BezierPoint *points, + int subdivisions, + BezierDistance *bdist) +{ + BezierMatrix geometry; + BezierMatrix tmp1, tmp2; + BezierMatrix deltas; + double x, dx, dx2, dx3; + double y, dy, dy2, dy3; + double d, d2, d3; + int index; + int i; + + /* construct the geometry matrix from the segment */ + /* assumes that a valid segment containing 4 points is passed in */ + + if(bdist->found) + return; + + for (i = 0; i < 4; i++) + { + if (!points) + fatal_error (_("bad bezier segment")); + + geometry[i][0] = points->x; + geometry[i][1] = points->y; + geometry[i][2] = 0; + geometry[i][3] = 0; + + points = points->next; + } + + /* subdivide the curve n times */ + /* n can be adjusted to give a finer or coarser curve */ + + d = 1.0 / subdivisions; + d2 = d * d; + d3 = d * d * d; + + /* construct a temporary matrix for determining the forward diffencing deltas */ + + tmp2[0][0] = 0; tmp2[0][1] = 0; tmp2[0][2] = 0; tmp2[0][3] = 1; + tmp2[1][0] = d3; tmp2[1][1] = d2; tmp2[1][2] = d; tmp2[1][3] = 0; + tmp2[2][0] = 6*d3; tmp2[2][1] = 2*d2; tmp2[2][2] = 0; tmp2[2][3] = 0; + tmp2[3][0] = 6*d3; tmp2[3][1] = 0; tmp2[3][2] = 0; tmp2[3][3] = 0; + + /* compose the basis and geometry matrices */ + bezier_compose (basis, geometry, tmp1); + + /* compose the above results to get the deltas matrix */ + bezier_compose (tmp2, tmp1, deltas); + + /* extract the x deltas */ + x = deltas[0][0]; + dx = deltas[1][0]; + dx2 = deltas[2][0]; + dx3 = deltas[3][0]; + + /* extract the y deltas */ + y = deltas[0][1]; + dy = deltas[1][1]; + dy2 = deltas[2][1]; + dy3 = deltas[3][1]; + + index = 1; + + /* loop over the curve */ + for (i = 0; i < subdivisions; i++) + { + /* increment the x values */ + x += dx; + dx += dx2; + dx2 += dx3; + + /* increment the y values */ + y += dy; + dy += dy2; + dy2 += dy3; + +/* printf("x = %g, y = %g\n",x,y); */ + + /* if this point is different than the last one...then draw it */ + /* Note : + * It assumes the udata is the place we want the + * floating version of the coords to be stuffed. + * These are needed when we calculate the gradient of the + * curve. + */ + + if(!bdist->firstpnt) + { + gdouble rx = x; + gdouble ry = y; + gdouble dx = bdist->lastx - rx; + gdouble dy = bdist->lasty - ry; + + bdist->curdist += sqrt((dx*dx)+(dy*dy)); + if(bdist->curdist >= bdist->dist) + { + *(bdist->x) = (gint)ROUND((rx + dx/2)); + *(bdist->y) = (gint)ROUND((ry + dy/2)); + if(dx == 0.0) + *(bdist->gradient) = G_MAXDOUBLE; + else + *(bdist->gradient) = dy/dx; + +/* printf("found x = %d, y = %d\n",*(bdist->x),*(bdist->y)); */ + bdist->found = TRUE; + break; + } + bdist->lastx = rx; + bdist->lasty = ry; + } + else + { + bdist->firstpnt = FALSE; + bdist->lastx = x; + bdist->lasty = y; + } + } +} + +static void +bezier_draw_curve_for_distance (BezierSelect *bezier_sel, + BezierDistance *udata) +{ + BezierPoint * points; + BezierPoint * start_pt; + int num_points; + + points = bezier_sel->points; + + if (bezier_sel->closed) + { + start_pt = bezier_sel->points; + + do { + bezier_draw_segment_for_distance (bezier_sel, points, + SUBDIVIDE, + udata); + + points = points->next; + points = points->next; + points = points->next; + } while (points != start_pt); + } + else + { + num_points = bezier_sel->num_points; + + while (num_points >= 4) + { + bezier_draw_segment_for_distance (bezier_sel, points, + SUBDIVIDE, + udata); + points = points->next; + points = points->next; + points = points->next; + num_points -= 3; + } + } +} + +gint +bezier_distance_along(BezierSelect *bezier_sel, + int open_path, + gdouble dist, + gint *x, + gint *y, + gdouble *gradient) +{ + /* Render the curve as points then walk along it... */ + BezierDistance *bdist = g_new0(BezierDistance,1); + gint ret; + + bdist->firstpnt = TRUE; + bdist->curdist = 0.0; + bdist->lastx = 0.0; + bdist->lasty = 0.0; + bdist->dist = dist; + bdist->x = x; + bdist->y = y; + bdist->gradient = gradient; + bdist->found = FALSE; + + bezier_draw_curve_for_distance (bezier_sel,bdist); + ret = bdist->found; + + g_free(bdist); + return (ret); } diff --git a/app/bezier_selectP.h b/app/bezier_selectP.h index 2ddd362d92..e472fda84e 100644 --- a/app/bezier_selectP.h +++ b/app/bezier_selectP.h @@ -63,17 +63,17 @@ struct _bezier_select GSList **scanlines; /* used in converting a curve */ }; -typedef void (*BezierPointsFunc) (BezierSelect *, GdkPoint *, int); +typedef void (*BezierPointsFunc) (BezierSelect *, GdkPoint *, int,gpointer); /* Functions */ int bezier_select_load (void *, BezierPoint *, int, int); -void bezier_draw_curve (BezierSelect *,BezierPointsFunc, int); +void bezier_draw_curve (BezierSelect *,BezierPointsFunc, int,gpointer); void bezier_select_reset (BezierSelect *); void bezier_add_point (BezierSelect *, int, int, int); void bezier_paste_bezierselect_to_current (GDisplay *,BezierSelect *); void bezier_select_mode (gint); void bezier_stroke (BezierSelect *, GDisplay *, int, int); void bezier_to_selection (BezierSelect *, GDisplay *); - +gint bezier_distance_along (BezierSelect *, gint, gdouble,gint *,gint *,gdouble *); #endif /* __BEZIER_SELECTP_H__ */ diff --git a/app/display/gimpdisplay-scroll.c b/app/display/gimpdisplay-scroll.c index c1125f7475..4d3088acee 100644 --- a/app/display/gimpdisplay-scroll.c +++ b/app/display/gimpdisplay-scroll.c @@ -85,6 +85,11 @@ void grab_and_scroll (GDisplay *gdisp, GdkEventMotion *mevent) { + if(mevent && mevent->window != gdisp->canvas->window) + { + return; + } + scroll_display (gdisp, (startx - mevent->x - gdisp->offset_x), (starty - mevent->y - gdisp->offset_y)); } diff --git a/app/display/gimpdisplayshell-scroll.c b/app/display/gimpdisplayshell-scroll.c index c1125f7475..4d3088acee 100644 --- a/app/display/gimpdisplayshell-scroll.c +++ b/app/display/gimpdisplayshell-scroll.c @@ -85,6 +85,11 @@ void grab_and_scroll (GDisplay *gdisp, GdkEventMotion *mevent) { + if(mevent && mevent->window != gdisp->canvas->window) + { + return; + } + scroll_display (gdisp, (startx - mevent->x - gdisp->offset_x), (starty - mevent->y - gdisp->offset_y)); } diff --git a/app/gui/paths-dialog.c b/app/gui/paths-dialog.c index 1d57af1845..d08b0a3dee 100644 --- a/app/gui/paths-dialog.c +++ b/app/gui/paths-dialog.c @@ -102,6 +102,8 @@ typedef struct { PATHP bzp; } PATHWIDGET, *PATHWIDGETP; +static gchar * unique_name(gchar *); + static gint path_widget_preview_events (GtkWidget *, GdkEvent *); static void paths_dialog_realized (GtkWidget *widget); static void paths_select_row (GtkWidget *widget,gint row,gint column,GdkEventButton *event,gpointer data); @@ -386,17 +388,22 @@ path_free(gpointer data,gpointer user_data) } static PATHP -bzpath_dialog_new(gint name_seed, gpointer udata) +path_dialog_new(GimpImage *gimage,gint name_seed, gpointer udata) { - PATHP bzp = g_new0(PATH,1); - + PATHP bzp; GString *s = g_string_new (NULL); + gchar *suniq; g_string_sprintf (s, "path %d",name_seed); - - bzp->pathtype = BEZIER; - bzp->name = s; - bzp->path_details = (GSList *)udata; /* If called via button/menu this will be NULL */ + suniq = unique_name(s->str); + if(suniq) + { + g_string_free(s,TRUE); + s = g_string_new(suniq); + g_free(suniq); + } + bzp = path_new(gimage,BEZIER,(GSList *)udata,0,0,0,0,s->str); + g_string_free(s,TRUE); return bzp; } @@ -493,7 +500,7 @@ unique_name(gchar *cstr) } static PATHP -path_copy(PATHP p) +path_copy(GimpImage *gimage,PATHP p) { PATHP p_copy = g_new0(PATH,1); gchar *ext; @@ -505,7 +512,7 @@ path_copy(PATHP p) p_copy->state = p->state; p_copy->pathtype = p->pathtype; p_copy->path_details = pathpoints_copy(p->path_details); - + p_copy->tattoo = gimp_image_get_new_tattoo(gimage); return p_copy; } @@ -1148,7 +1155,7 @@ static PATHP paths_dialog_new_path(PATHIMAGELISTP *plp,gpointer points,GimpImage *gimage,gint pos) { static gint nseed = 0; - PATHP bzp = bzpath_dialog_new(nseed++,points); + PATHP bzp = path_dialog_new(gimage,nseed++,points); *plp = path_add_to_current(*plp,bzp,gimage,pos); return(bzp); } @@ -1239,7 +1246,7 @@ paths_dialog_dup_path_callback (GtkWidget * widget, gpointer udata) bzp = (PATHP)g_slist_nth_data(plp->bz_paths,row); /* Insert at the current position */ - bzp = path_copy(bzp); + bzp = path_copy(paths_dialog->gimage,bzp); plp->bz_paths = g_slist_insert(plp->bz_paths,bzp,row); paths_add_path(bzp,row); @@ -1277,7 +1284,7 @@ paths_dialog_path_to_sel_callback (GtkWidget * widget, gpointer udata) if(!bzp->closed) { - PATHP bzpcopy = path_copy(bzp); + PATHP bzpcopy = path_copy(paths_dialog->gimage,bzp); /* Close it */ path_close(bzpcopy); bezier_sel = path_to_beziersel(bzpcopy); @@ -1449,8 +1456,9 @@ paths_replaced_current(PATHIMAGELISTP plp,BezierSelect *bezier_sel) static void paths_draw_segment_points(BezierSelect *bezier_sel, - GdkPoint *pnt, - int npoints) + GdkPoint *pnt, + int npoints, + gpointer udata) { /* * hopefully the image points are already in image space co-ords. @@ -1520,7 +1528,7 @@ paths_update_preview(BezierSelect *bezier_sel) clear_pixmap_preview(pwidget); /* update .. */ - bezier_draw_curve (bezier_sel,paths_draw_segment_points,IMAGE_COORDS); + bezier_draw_curve (bezier_sel,paths_draw_segment_points,IMAGE_COORDS,NULL); /* update the pixmap */ @@ -1661,12 +1669,14 @@ pathpoint_new(gint type, } PATHP -path_new(PathType ptype, - GSList * path_details, - gint closed, - gint state, - gint locked, - gchar * name) +path_new(GimpImage *gimage, + PathType ptype, + GSList *path_details, + gint closed, + gint state, + gint locked, + gint tattoo, + gchar *name) { PATHP path = g_new0(PATH,1); @@ -1676,6 +1686,10 @@ path_new(PathType ptype, path->locked = locked; path->name = g_string_new(name); path->pathtype = ptype; + if(tattoo) + path->tattoo = tattoo; + else + path->tattoo = gimp_image_get_new_tattoo(gimage); return path; } @@ -1789,11 +1803,13 @@ static void file_ok_callback(GtkWidget * widget, gpointer client_data) pts_list = g_slist_append(pts_list,bpt); } - bzpath = path_new(BEZIER, + bzpath = path_new(paths_dialog->gimage, + BEZIER, pts_list, closed, state, 0, /* Can't be locked */ + 0, /* No tattoo assigned */ txt); g_free(txtstart); @@ -2027,11 +2043,13 @@ paths_set_path_points(GimpImage * gimage, { GSList *bzp_list = NULL; /* No paths at all.... create one & rename */ - bzpath = path_new(ptype, + bzpath = path_new(gimage, + ptype, pts_list, pclosed, (pclosed)?BEZIER_EDIT:BEZIER_ADD,/*state,*/ 0, /* Can't be locked */ + 0, /* No tattoo assigned */ pname); bzp_list = g_slist_append(bzp_list,bzpath); plist = pathsList_new(gimage,0,bzp_list); @@ -2075,11 +2093,13 @@ paths_set_path_points(GimpImage * gimage, } else { - bzpath = path_new(ptype, + bzpath = path_new(gimage, + ptype, pts_list, pclosed, (pclosed)?BEZIER_EDIT:BEZIER_ADD,/*state,*/ 0, /* Can't be locked */ + 0, /* No tattoo assigned */ pname); path_add_to_current(plist,bzpath,gimage,-1); @@ -2123,3 +2143,55 @@ paths_stroke(GimpImage *gimage,PathsList *pl,PATHP bzp) bezier_stroke (bezier_sel, gdisp, SUBDIVIDE, !bzp->closed); beziersel_free(bezier_sel); } + +gint +paths_distance(PATHP bzp,gdouble dist,gint *x,gint *y, gdouble *grad) +{ + gint ret; + BezierSelect * bezier_sel; + bezier_sel = path_to_beziersel(bzp); + ret = bezier_distance_along(bezier_sel,!bzp->closed,dist,x,y,grad); + beziersel_free(bezier_sel); + return(ret); +} + +Tattoo +paths_get_tattoo(PATHP p) +{ + if(!p) + { + g_warning(_("paths_get_tattoo: invalid path")); + return 0; + } + + return (p->tattoo); +} + +PATHP +paths_get_path_by_tattoo(GimpImage *gimage,Tattoo tattoo) +{ + GSList *tlist; + PATHIMAGELISTP plp; + + if(!gimage || !tattoo) + return NULL; + + /* Go around the list and check all tattoos. */ + + /* Get path structure */ + plp = (PATHIMAGELISTP)gimp_image_get_paths(gimage); + + if(!plp) + return (NULL); + + tlist = plp->bz_paths; + + while(tlist) + { + PATHP p = (PATHP)(tlist->data); + if(p->tattoo == tattoo) + return (p); + tlist = g_slist_next(tlist); + } + return (NULL); +} diff --git a/app/move.c b/app/move.c index 4a8936df32..743a5f890c 100644 --- a/app/move.c +++ b/app/move.c @@ -262,6 +262,12 @@ move_tool_motion (Tool *tool, if (private->guide) { move_draw_guide (gdisp, private->guide); + + if(mevent && mevent->window != gdisp->canvas->window) + { + private->guide->position = -1; + return; + } if (mevent) { diff --git a/app/pathsP.h b/app/pathsP.h index cba368eb5b..e17b082faf 100644 --- a/app/pathsP.h +++ b/app/pathsP.h @@ -34,6 +34,7 @@ typedef struct { gboolean closed; guint32 state; guint32 locked; /* Only bottom bit used */ + Tattoo tattoo; /* The tattoo for the path */ GString * name; } PATH, *PATHP; @@ -58,11 +59,14 @@ typedef enum { } PathType; PATHPOINTP pathpoint_new(gint,gdouble,gdouble); -PATHP path_new(PathType,GSList *,gint,gint,gint,gchar *); +PATHP path_new(GimpImage *,PathType,GSList *,gint,gint,gint,gint,gchar *); PathsList * pathsList_new(GimpImage *,gint,GSList *); gboolean paths_set_path(GimpImage *,gchar *); gboolean paths_set_path_points(GimpImage *,gchar *,gint,gint,gint,gdouble *); void paths_stroke(GimpImage *,PathsList *,PATHP); +gint paths_distance(PATHP ,gdouble ,gint *,gint *, gdouble *); +Tattoo paths_get_tattoo(PATHP); +PATHP paths_get_path_by_tattoo(GimpImage *,Tattoo); #endif /* __PATHSP_H__ */ diff --git a/app/paths_cmds.c b/app/paths_cmds.c index ca5d06c333..d0e8115dcd 100644 --- a/app/paths_cmds.c +++ b/app/paths_cmds.c @@ -29,6 +29,9 @@ static ProcRecord path_get_current_proc; static ProcRecord path_set_current_proc; static ProcRecord path_set_points_proc; static ProcRecord path_stroke_current_proc; +static ProcRecord path_get_point_at_dist_proc; +static ProcRecord path_get_tattoo_proc; +static ProcRecord get_path_by_tattoo_proc; void register_paths_procs (void) @@ -39,6 +42,9 @@ register_paths_procs (void) procedural_db_register (&path_set_current_proc); procedural_db_register (&path_set_points_proc); procedural_db_register (&path_stroke_current_proc); + procedural_db_register (&path_get_point_at_dist_proc); + procedural_db_register (&path_get_tattoo_proc); + procedural_db_register (&get_path_by_tattoo_proc); } static Argument * @@ -525,3 +531,278 @@ static ProcRecord path_stroke_current_proc = NULL, { { path_stroke_current_invoker } } }; + +static Argument * +path_get_point_at_dist_invoker (Argument *args) +{ + gboolean success = TRUE; + Argument *return_args; + GimpImage *gimage; + gdouble distance; + gint32 x_point = 0; + gint32 y_point = 0; + gdouble gradient = 0; + + gimage = pdb_id_to_image (args[0].value.pdb_int); + if (gimage == NULL) + success = FALSE; + + distance = args[1].value.pdb_float; + + if (success) + { + /* Get the path with the given name */ + PathsList *plist = gimage->paths; + + if(plist && plist->bz_paths) + { + PATHP pptr = NULL; + + if(plist->last_selected_row >= 0) + { + pptr = (PATHP)g_slist_nth_data(plist->bz_paths,plist->last_selected_row); + success = paths_distance(pptr,distance,&x_point,&y_point,&gradient); + } + else + { + success = FALSE; + } + } + else + { + success = FALSE; + } + } + + return_args = procedural_db_return_args (&path_get_point_at_dist_proc, success); + + if (success) + { + return_args[1].value.pdb_int = x_point; + return_args[2].value.pdb_int = y_point; + return_args[3].value.pdb_float = gradient; + } + + return return_args; +} + +static ProcArg path_get_point_at_dist_inargs[] = +{ + { + PDB_IMAGE, + "image", + "The ID of the image the paths belongs to" + }, + { + PDB_FLOAT, + "distance", + "The distance along the path" + } +}; + +static ProcArg path_get_point_at_dist_outargs[] = +{ + { + PDB_INT32, + "x_point", + "The x position of the point" + }, + { + PDB_INT32, + "y_point", + "The y position of the point" + }, + { + PDB_FLOAT, + "gradient", + "The gradient at the specified point" + } +}; + +static ProcRecord path_get_point_at_dist_proc = +{ + "gimp_path_get_point_at_dist", + "Get point on a path at a specified distance along the path", + "This will return the x,y position of a point at a given distance along the bezier curve. The distance will the obtained by first digitizing the curve internally an then walking along the curve. For a closed curve the start of the path is the first point on the path that was created. This might not be obvious. Note the current path is used.", + "Andy Thomas", + "Andy Thomas", + "1999", + PDB_INTERNAL, + 2, + path_get_point_at_dist_inargs, + 3, + path_get_point_at_dist_outargs, + { { path_get_point_at_dist_invoker } } +}; + +static Argument * +path_get_tattoo_invoker (Argument *args) +{ + gboolean success = TRUE; + Argument *return_args; + GimpImage *gimage; + gchar *pname; + gint32 tattoo = 0; + PathsList *plist; + + gimage = pdb_id_to_image (args[0].value.pdb_int); + if (gimage == NULL) + success = FALSE; + + pname = (gchar *) args[1].value.pdb_pointer; + if (pname == NULL) + success = FALSE; + + if (success) + { + PATHP pptr = NULL; + /* Get the path with the given name */ + plist = gimage->paths; + + if (plist && plist->bz_paths) + { + GSList *pl = plist->bz_paths; + + while (pl) + { + pptr = pl->data; + + if (strcmp (pname, pptr->name->str) == 0) + break; /* Found the path */ + + pl = pl->next; + pptr = NULL; + } + + if (pl && pptr) + { + tattoo = paths_get_tattoo(pptr); + } + else + success = FALSE; + } + } + + return_args = procedural_db_return_args (&path_get_tattoo_proc, success); + + if (success) + return_args[1].value.pdb_int = tattoo; + + return return_args; +} + +static ProcArg path_get_tattoo_inargs[] = +{ + { + PDB_IMAGE, + "image", + "The ID of the image" + }, + { + PDB_STRING, + "pathname", + "the name of the path whose tattoo should be obtained" + } +}; + +static ProcArg path_get_tattoo_outargs[] = +{ + { + PDB_INT32, + "tattoo", + "The tattoo associated with the name path" + } +}; + +static ProcRecord path_get_tattoo_proc = +{ + "gimp_path_get_tattoo", + "Returns the tattoo associated with the name path", + "This procedure returns the tattoo associated with the specified path. A tattoo is a unique and permenant identifier attached to a path that can be used to uniquely identify a path within an image even between sessions.", + "Andy Thomas", + "Andy Thomas", + "1999", + PDB_INTERNAL, + 2, + path_get_tattoo_inargs, + 1, + path_get_tattoo_outargs, + { { path_get_tattoo_invoker } } +}; + +static Argument * +get_path_by_tattoo_invoker (Argument *args) +{ + gboolean success = TRUE; + Argument *return_args; + GimpImage *gimage; + gint32 tattoo; + PathsList *plist; + PATHP pptr = NULL; + + gimage = pdb_id_to_image (args[0].value.pdb_int); + if (gimage == NULL) + success = FALSE; + + tattoo = args[1].value.pdb_int; + + if (success) + { + /* Get the path with the given name */ + plist = gimage->paths; + + if (plist && plist->bz_paths) + { + if((pptr = paths_get_path_by_tattoo(gimage,tattoo)) == NULL) + success = FALSE; + } + else + success = FALSE; + } + + return_args = procedural_db_return_args (&get_path_by_tattoo_proc, success); + + if (success) + return_args[1].value.pdb_pointer = g_strdup (pptr->name->str); + + return return_args; +} + +static ProcArg get_path_by_tattoo_inargs[] = +{ + { + PDB_IMAGE, + "image", + "The ID of the image" + }, + { + PDB_INT32, + "tattoo", + "The tattoo of the required path" + } +}; + +static ProcArg get_path_by_tattoo_outargs[] = +{ + { + PDB_STRING, + "path_name", + "The name of the path with the specified tattoo" + } +}; + +static ProcRecord get_path_by_tattoo_proc = +{ + "gimp_get_path_by_tattoo", + "Return the name of the path with the given tattoo", + "The procedure returns the name of the path in the specified image which has the passed tattoo. The tattoos are unique within the image and will be preserved across sessions and through renaming of the path. An error is returned if no path woth the specified tattoo can be found.", + "Andy Thomas", + "Andy Thomas", + "1999", + PDB_INTERNAL, + 2, + get_path_by_tattoo_inargs, + 1, + get_path_by_tattoo_outargs, + { { get_path_by_tattoo_invoker } } +}; diff --git a/app/paths_dialog.c b/app/paths_dialog.c index 1d57af1845..d08b0a3dee 100644 --- a/app/paths_dialog.c +++ b/app/paths_dialog.c @@ -102,6 +102,8 @@ typedef struct { PATHP bzp; } PATHWIDGET, *PATHWIDGETP; +static gchar * unique_name(gchar *); + static gint path_widget_preview_events (GtkWidget *, GdkEvent *); static void paths_dialog_realized (GtkWidget *widget); static void paths_select_row (GtkWidget *widget,gint row,gint column,GdkEventButton *event,gpointer data); @@ -386,17 +388,22 @@ path_free(gpointer data,gpointer user_data) } static PATHP -bzpath_dialog_new(gint name_seed, gpointer udata) +path_dialog_new(GimpImage *gimage,gint name_seed, gpointer udata) { - PATHP bzp = g_new0(PATH,1); - + PATHP bzp; GString *s = g_string_new (NULL); + gchar *suniq; g_string_sprintf (s, "path %d",name_seed); - - bzp->pathtype = BEZIER; - bzp->name = s; - bzp->path_details = (GSList *)udata; /* If called via button/menu this will be NULL */ + suniq = unique_name(s->str); + if(suniq) + { + g_string_free(s,TRUE); + s = g_string_new(suniq); + g_free(suniq); + } + bzp = path_new(gimage,BEZIER,(GSList *)udata,0,0,0,0,s->str); + g_string_free(s,TRUE); return bzp; } @@ -493,7 +500,7 @@ unique_name(gchar *cstr) } static PATHP -path_copy(PATHP p) +path_copy(GimpImage *gimage,PATHP p) { PATHP p_copy = g_new0(PATH,1); gchar *ext; @@ -505,7 +512,7 @@ path_copy(PATHP p) p_copy->state = p->state; p_copy->pathtype = p->pathtype; p_copy->path_details = pathpoints_copy(p->path_details); - + p_copy->tattoo = gimp_image_get_new_tattoo(gimage); return p_copy; } @@ -1148,7 +1155,7 @@ static PATHP paths_dialog_new_path(PATHIMAGELISTP *plp,gpointer points,GimpImage *gimage,gint pos) { static gint nseed = 0; - PATHP bzp = bzpath_dialog_new(nseed++,points); + PATHP bzp = path_dialog_new(gimage,nseed++,points); *plp = path_add_to_current(*plp,bzp,gimage,pos); return(bzp); } @@ -1239,7 +1246,7 @@ paths_dialog_dup_path_callback (GtkWidget * widget, gpointer udata) bzp = (PATHP)g_slist_nth_data(plp->bz_paths,row); /* Insert at the current position */ - bzp = path_copy(bzp); + bzp = path_copy(paths_dialog->gimage,bzp); plp->bz_paths = g_slist_insert(plp->bz_paths,bzp,row); paths_add_path(bzp,row); @@ -1277,7 +1284,7 @@ paths_dialog_path_to_sel_callback (GtkWidget * widget, gpointer udata) if(!bzp->closed) { - PATHP bzpcopy = path_copy(bzp); + PATHP bzpcopy = path_copy(paths_dialog->gimage,bzp); /* Close it */ path_close(bzpcopy); bezier_sel = path_to_beziersel(bzpcopy); @@ -1449,8 +1456,9 @@ paths_replaced_current(PATHIMAGELISTP plp,BezierSelect *bezier_sel) static void paths_draw_segment_points(BezierSelect *bezier_sel, - GdkPoint *pnt, - int npoints) + GdkPoint *pnt, + int npoints, + gpointer udata) { /* * hopefully the image points are already in image space co-ords. @@ -1520,7 +1528,7 @@ paths_update_preview(BezierSelect *bezier_sel) clear_pixmap_preview(pwidget); /* update .. */ - bezier_draw_curve (bezier_sel,paths_draw_segment_points,IMAGE_COORDS); + bezier_draw_curve (bezier_sel,paths_draw_segment_points,IMAGE_COORDS,NULL); /* update the pixmap */ @@ -1661,12 +1669,14 @@ pathpoint_new(gint type, } PATHP -path_new(PathType ptype, - GSList * path_details, - gint closed, - gint state, - gint locked, - gchar * name) +path_new(GimpImage *gimage, + PathType ptype, + GSList *path_details, + gint closed, + gint state, + gint locked, + gint tattoo, + gchar *name) { PATHP path = g_new0(PATH,1); @@ -1676,6 +1686,10 @@ path_new(PathType ptype, path->locked = locked; path->name = g_string_new(name); path->pathtype = ptype; + if(tattoo) + path->tattoo = tattoo; + else + path->tattoo = gimp_image_get_new_tattoo(gimage); return path; } @@ -1789,11 +1803,13 @@ static void file_ok_callback(GtkWidget * widget, gpointer client_data) pts_list = g_slist_append(pts_list,bpt); } - bzpath = path_new(BEZIER, + bzpath = path_new(paths_dialog->gimage, + BEZIER, pts_list, closed, state, 0, /* Can't be locked */ + 0, /* No tattoo assigned */ txt); g_free(txtstart); @@ -2027,11 +2043,13 @@ paths_set_path_points(GimpImage * gimage, { GSList *bzp_list = NULL; /* No paths at all.... create one & rename */ - bzpath = path_new(ptype, + bzpath = path_new(gimage, + ptype, pts_list, pclosed, (pclosed)?BEZIER_EDIT:BEZIER_ADD,/*state,*/ 0, /* Can't be locked */ + 0, /* No tattoo assigned */ pname); bzp_list = g_slist_append(bzp_list,bzpath); plist = pathsList_new(gimage,0,bzp_list); @@ -2075,11 +2093,13 @@ paths_set_path_points(GimpImage * gimage, } else { - bzpath = path_new(ptype, + bzpath = path_new(gimage, + ptype, pts_list, pclosed, (pclosed)?BEZIER_EDIT:BEZIER_ADD,/*state,*/ 0, /* Can't be locked */ + 0, /* No tattoo assigned */ pname); path_add_to_current(plist,bzpath,gimage,-1); @@ -2123,3 +2143,55 @@ paths_stroke(GimpImage *gimage,PathsList *pl,PATHP bzp) bezier_stroke (bezier_sel, gdisp, SUBDIVIDE, !bzp->closed); beziersel_free(bezier_sel); } + +gint +paths_distance(PATHP bzp,gdouble dist,gint *x,gint *y, gdouble *grad) +{ + gint ret; + BezierSelect * bezier_sel; + bezier_sel = path_to_beziersel(bzp); + ret = bezier_distance_along(bezier_sel,!bzp->closed,dist,x,y,grad); + beziersel_free(bezier_sel); + return(ret); +} + +Tattoo +paths_get_tattoo(PATHP p) +{ + if(!p) + { + g_warning(_("paths_get_tattoo: invalid path")); + return 0; + } + + return (p->tattoo); +} + +PATHP +paths_get_path_by_tattoo(GimpImage *gimage,Tattoo tattoo) +{ + GSList *tlist; + PATHIMAGELISTP plp; + + if(!gimage || !tattoo) + return NULL; + + /* Go around the list and check all tattoos. */ + + /* Get path structure */ + plp = (PATHIMAGELISTP)gimp_image_get_paths(gimage); + + if(!plp) + return (NULL); + + tlist = plp->bz_paths; + + while(tlist) + { + PATHP p = (PATHP)(tlist->data); + if(p->tattoo == tattoo) + return (p); + tlist = g_slist_next(tlist); + } + return (NULL); +} diff --git a/app/scroll.c b/app/scroll.c index c1125f7475..4d3088acee 100644 --- a/app/scroll.c +++ b/app/scroll.c @@ -85,6 +85,11 @@ void grab_and_scroll (GDisplay *gdisp, GdkEventMotion *mevent) { + if(mevent && mevent->window != gdisp->canvas->window) + { + return; + } + scroll_display (gdisp, (startx - mevent->x - gdisp->offset_x), (starty - mevent->y - gdisp->offset_y)); } diff --git a/app/tools/bezier_select.c b/app/tools/bezier_select.c index 85a58ff5b4..9863ef7002 100644 --- a/app/tools/bezier_select.c +++ b/app/tools/bezier_select.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "appenv.h" #include "draw_core.h" #include "edit_selection.h" @@ -61,6 +62,8 @@ #define NO 0 #define YES 1 +#define ROUND(x) ((int) ((x) + 0.5)) + /* bezier select type definitions */ typedef double BezierMatrix[4][4]; @@ -84,6 +87,24 @@ struct _named_buffer char * name; }; +typedef struct { + gdouble *stroke_points; + gint num_stroke_points; /* num of valid points */ + gint len_stroke_points; /* allocated length */ +} BezierRenderPnts; + +typedef struct { + gboolean firstpnt; + gdouble curdist; + gdouble dist; + gdouble *gradient; + gint *x; + gint *y; + gdouble lastx; + gdouble lasty; + gboolean found; +} BezierDistance; + static void bezier_select_button_press (Tool *, GdkEventButton *, gpointer); static void bezier_select_button_release (Tool *, GdkEventButton *, gpointer); static void bezier_select_motion (Tool *, GdkEventMotion *, gpointer); @@ -96,20 +117,20 @@ static void bezier_draw_handles (BezierSelect *); static void bezier_draw_current (BezierSelect *); static void bezier_draw_point (BezierSelect *, BezierPoint *, int); static void bezier_draw_line (BezierSelect *, BezierPoint *, BezierPoint *); -static void bezier_draw_segment (BezierSelect *, BezierPoint *, int, int, BezierPointsFunc); -static void bezier_draw_segment_points (BezierSelect *, GdkPoint *, int); +static void bezier_draw_segment (BezierSelect *, BezierPoint *, int, int, BezierPointsFunc,gpointer); +static void bezier_draw_segment_points (BezierSelect *, GdkPoint *, int, gpointer); static void bezier_compose (BezierMatrix, BezierMatrix, BezierMatrix); static void bezier_convert (BezierSelect *, GDisplay *, int, int); -static void bezier_convert_points (BezierSelect *, GdkPoint *, int); +static void bezier_convert_points (BezierSelect *, GdkPoint *, int, gpointer); static void bezier_convert_line (GSList **, int, int, int, int); 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 void bezier_stack_points (BezierSelect *, GdkPoint *, int, gpointer); static gboolean stroke_interpolatable (int, int, int, int, gdouble); -static void bezier_stack_points_aux (GdkPoint *, int, int, gdouble); +static void bezier_stack_points_aux (GdkPoint *, int, int, gdouble, BezierRenderPnts *); static BezierMatrix basis = { @@ -233,7 +254,10 @@ bezier_select_load (void *gdisp_ptr, } void -bezier_draw_curve (BezierSelect *bezier_sel,BezierPointsFunc func, gint coord) +bezier_draw_curve (BezierSelect *bezier_sel, + BezierPointsFunc func, + gint coord, + gpointer udata) { BezierPoint * points; BezierPoint * start_pt; @@ -248,7 +272,8 @@ bezier_draw_curve (BezierSelect *bezier_sel,BezierPointsFunc func, gint coord) do { bezier_draw_segment (bezier_sel, points, SUBDIVIDE, coord, - func); + func, + udata); points = points->next; points = points->next; @@ -263,7 +288,8 @@ bezier_draw_curve (BezierSelect *bezier_sel,BezierPointsFunc func, gint coord) { bezier_draw_segment (bezier_sel, points, SUBDIVIDE, coord, - func); + func, + udata); points = points->next; points = points->next; @@ -447,7 +473,7 @@ bezier_add_point_on_segment(int x, if (test_add_point_on_segment (bezier_sel, points, SUBDIVIDE, - SCREEN_COORDS, + IMAGE_COORDS, x, y, halfwidth)) { @@ -953,7 +979,7 @@ bezier_select_draw (Tool *tool) } if (draw_curve) - bezier_draw_curve (bezier_sel,bezier_draw_segment_points,SCREEN_COORDS); + bezier_draw_curve (bezier_sel,bezier_draw_segment_points,SCREEN_COORDS,NULL); if (draw_handles) bezier_draw_handles (bezier_sel); if (draw_current) @@ -1082,7 +1108,8 @@ bezier_draw_current (BezierSelect *bezier_sel) if (points) bezier_draw_segment (bezier_sel, points, SUBDIVIDE, SCREEN_COORDS, - bezier_draw_segment_points); + bezier_draw_segment_points, + NULL); if (points != bezier_sel->cur_anchor) { @@ -1095,7 +1122,8 @@ bezier_draw_current (BezierSelect *bezier_sel) if (points) bezier_draw_segment (bezier_sel, bezier_sel->cur_anchor, SUBDIVIDE, SCREEN_COORDS, - bezier_draw_segment_points); + bezier_draw_segment_points, + NULL); } } @@ -1158,7 +1186,8 @@ bezier_draw_segment (BezierSelect *bezier_sel, BezierPoint *points, int subdivisions, int space, - BezierPointsFunc points_func) + BezierPointsFunc points_func, + gpointer udata) { #define ROUND(x) ((int) ((x) + 0.5)) @@ -1275,7 +1304,7 @@ bezier_draw_segment (BezierSelect *bezier_sel, /* if the point buffer is full put it to the screen and zero it out */ if (index >= npoints) { - (* points_func) (bezier_sel, gdk_points, index); + (* points_func) (bezier_sel, gdk_points, index, udata); index = 0; } } @@ -1286,13 +1315,14 @@ bezier_draw_segment (BezierSelect *bezier_sel, /* if there are points in the buffer, then put them on the screen */ if (index) - (* points_func) (bezier_sel, gdk_points, index); + (* points_func) (bezier_sel, gdk_points, index, udata); } static void bezier_draw_segment_points (BezierSelect *bezier_sel, GdkPoint *points, - int npoints) + int npoints, + gpointer udata) { gdk_draw_points (bezier_sel->core->win, bezier_sel->core->gc, points, npoints); @@ -1388,7 +1418,8 @@ bezier_convert (BezierSelect *bezier_sel, do { bezier_draw_segment (bezier_sel, points, subdivisions, draw_type, - bezier_convert_points); + bezier_convert_points, + NULL); /* advance to the next segment */ points = points->next; @@ -1478,7 +1509,8 @@ bezier_convert (BezierSelect *bezier_sel, static void bezier_convert_points (BezierSelect *bezier_sel, GdkPoint *points, - int npoints) + int npoints, + gpointer udata) { int i; @@ -1765,8 +1797,6 @@ test_add_point_on_segment (BezierSelect *bezier_sel, int halfwidth) { -#define ROUND(x) ((int) ((x) + 0.5)) - BezierPoint *points; BezierMatrix geometry; BezierMatrix tmp1, tmp2; @@ -2042,10 +2072,6 @@ void printSel( BezierSelect *sel) printf("state: %d\n", sel->state); } -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) @@ -2088,35 +2114,36 @@ static void bezier_stack_points_aux (GdkPoint *points, int start, int end, - gdouble error) + gdouble error, + BezierRenderPnts *rpnts) { const gint expand_size = 32; gint med; gint offx, offy, l_offx, l_offy; - if (stroke_points == NULL) + if (rpnts->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)) + if ((rpnts->stroke_points[rpnts->num_stroke_points * 2 - 2] == points[end].x) + && (rpnts->stroke_points[rpnts->num_stroke_points * 2 - 1] == points[end].y)) return; - num_stroke_points++; - if (len_stroke_points <= num_stroke_points) + rpnts->num_stroke_points++; + if (rpnts->len_stroke_points <= rpnts->num_stroke_points) { - len_stroke_points += expand_size; - stroke_points = g_renew (double, stroke_points, 2 * len_stroke_points); - if (stroke_points == NULL) + rpnts->len_stroke_points += expand_size; + rpnts->stroke_points = g_renew (double, rpnts->stroke_points, 2 * rpnts->len_stroke_points); + if (rpnts->stroke_points == NULL) { - len_stroke_points = num_stroke_points = 0; + rpnts->len_stroke_points = rpnts->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; + rpnts->stroke_points[rpnts->num_stroke_points * 2 - 2] = points[end].x; + rpnts->stroke_points[rpnts->num_stroke_points * 2 - 1] = points[end].y; return; } @@ -2125,7 +2152,7 @@ bezier_stack_points_aux (GdkPoint *points, gint i; for (i = start+ 1; i <= end; i++) - bezier_stack_points_aux (points, i, i, 0); + bezier_stack_points_aux (points, i, i, 0,rpnts); return; } /* Otherwise, check whether to divide the segment recursively */ @@ -2138,8 +2165,8 @@ bezier_stack_points_aux (GdkPoint *points, 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); + bezier_stack_points_aux (points, start, med, error, rpnts); + bezier_stack_points_aux (points, med, end, error, rpnts); return; } @@ -2148,33 +2175,35 @@ bezier_stack_points_aux (GdkPoint *points, 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); + bezier_stack_points_aux (points, start, med, error, rpnts); + bezier_stack_points_aux (points, med, end, error, rpnts); 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); + bezier_stack_points_aux (points, end, end, 0, rpnts); } static void bezier_stack_points (BezierSelect *bezier_sel, GdkPoint *points, - int npoints) + int npoints, + gpointer udata) { gint i; gint expand_size = 32; gint minx, maxx, miny, maxy; gdouble error; + BezierRenderPnts *rpnts = udata; if (npoints < 2) /* Does this happen? */ return; - if (stroke_points == NULL) /* initialize it here */ + if (rpnts->stroke_points == NULL) /* initialize it here */ { - num_stroke_points = 0; - len_stroke_points = expand_size; - stroke_points = g_new (double, 2 * len_stroke_points); + rpnts->num_stroke_points = 0; + rpnts->len_stroke_points = expand_size; + rpnts->stroke_points = g_new (double, 2 * rpnts->len_stroke_points); } maxx = minx = points[0].x; @@ -2194,41 +2223,39 @@ bezier_stack_points (BezierSelect *bezier_sel, error = 2.0 / MAX(maxx - minx, maxy - miny); /* add the start point */ - bezier_stack_points_aux (points, 0, 0, 0); + bezier_stack_points_aux (points, 0, 0, 0, rpnts); /* divide segments recursively */ - bezier_stack_points_aux (points, 0, npoints - 1, error); + bezier_stack_points_aux (points, 0, npoints - 1, error, rpnts); /* printf ("npoints: %d\n", npoints); */ } -void -bezier_stroke (BezierSelect *bezier_sel, - GDisplay *gdisp, - int subdivisions, - int open_path) +static gint +bezier_gen_points(BezierSelect *bezier_sel, + int open_path, + BezierRenderPnts *rpnts) { BezierPoint * points; int num_points; - Argument *return_vals; - int nreturn_vals; int redraw = FALSE; /* stack points */ points = bezier_sel->points; num_points = bezier_sel->num_points; - + if (bezier_sel->closed && (! open_path)) { BezierPoint * start_pt; - + start_pt = bezier_sel->points; - + do { bezier_draw_segment (bezier_sel, points, SUBDIVIDE, IMAGE_COORDS, - bezier_stack_points); - + bezier_stack_points, + (gpointer)rpnts); + points = points->next; points = points->next; points = points->next; @@ -2245,7 +2272,8 @@ bezier_stroke (BezierSelect *bezier_sel, { bezier_draw_segment (bezier_sel, points, SUBDIVIDE, IMAGE_COORDS, - bezier_stack_points); + bezier_stack_points, + (gpointer)rpnts); points = points->next; points = points->next; @@ -2254,7 +2282,23 @@ bezier_stroke (BezierSelect *bezier_sel, } } - if (stroke_points) + return (redraw); +} + +void +bezier_stroke (BezierSelect *bezier_sel, + GDisplay *gdisp, + int subdivisions, + int open_path) +{ + Argument *return_vals; + int nreturn_vals; + int redraw; + BezierRenderPnts *rpnts = g_new0(BezierRenderPnts,1); + + redraw = bezier_gen_points(bezier_sel,open_path,rpnts); + + if (rpnts->stroke_points) { GimpDrawable *drawable; int offset_x, offset_y; @@ -2266,8 +2310,8 @@ bezier_stroke (BezierSelect *bezier_sel, { gdouble *ptr; - ptr = stroke_points; - while (ptr < stroke_points + (num_stroke_points * 2)) + ptr = rpnts->stroke_points; + while (ptr < rpnts->stroke_points + (rpnts->num_stroke_points * 2)) { *ptr++ -= offset_x; *ptr++ -= offset_y; @@ -2278,8 +2322,8 @@ bezier_stroke (BezierSelect *bezier_sel, &nreturn_vals, PDB_DRAWABLE, drawable_ID (drawable), PDB_FLOAT, (gdouble) 0, - PDB_INT32, (gint32) num_stroke_points * 2, - PDB_FLOATARRAY, stroke_points, + PDB_INT32, (gint32) rpnts->num_stroke_points * 2, + PDB_FLOATARRAY, rpnts->stroke_points, PDB_END); if (return_vals[0].value.pdb_int == PDB_SUCCESS) @@ -2295,10 +2339,206 @@ bezier_stroke (BezierSelect *bezier_sel, procedural_db_destroy_args (return_vals, nreturn_vals); - g_free (stroke_points); + g_free (rpnts->stroke_points); } /* printf ("num_stroke_points: %d\ndone.\n", num_stroke_points); */ - stroke_points = NULL; - len_stroke_points = num_stroke_points = 0; + rpnts->stroke_points = NULL; + rpnts->len_stroke_points = rpnts->num_stroke_points = 0; + + g_free(rpnts); +} + +static void +bezier_draw_segment_for_distance (BezierSelect *bezier_sel, + BezierPoint *points, + int subdivisions, + BezierDistance *bdist) +{ + BezierMatrix geometry; + BezierMatrix tmp1, tmp2; + BezierMatrix deltas; + double x, dx, dx2, dx3; + double y, dy, dy2, dy3; + double d, d2, d3; + int index; + int i; + + /* construct the geometry matrix from the segment */ + /* assumes that a valid segment containing 4 points is passed in */ + + if(bdist->found) + return; + + for (i = 0; i < 4; i++) + { + if (!points) + fatal_error (_("bad bezier segment")); + + geometry[i][0] = points->x; + geometry[i][1] = points->y; + geometry[i][2] = 0; + geometry[i][3] = 0; + + points = points->next; + } + + /* subdivide the curve n times */ + /* n can be adjusted to give a finer or coarser curve */ + + d = 1.0 / subdivisions; + d2 = d * d; + d3 = d * d * d; + + /* construct a temporary matrix for determining the forward diffencing deltas */ + + tmp2[0][0] = 0; tmp2[0][1] = 0; tmp2[0][2] = 0; tmp2[0][3] = 1; + tmp2[1][0] = d3; tmp2[1][1] = d2; tmp2[1][2] = d; tmp2[1][3] = 0; + tmp2[2][0] = 6*d3; tmp2[2][1] = 2*d2; tmp2[2][2] = 0; tmp2[2][3] = 0; + tmp2[3][0] = 6*d3; tmp2[3][1] = 0; tmp2[3][2] = 0; tmp2[3][3] = 0; + + /* compose the basis and geometry matrices */ + bezier_compose (basis, geometry, tmp1); + + /* compose the above results to get the deltas matrix */ + bezier_compose (tmp2, tmp1, deltas); + + /* extract the x deltas */ + x = deltas[0][0]; + dx = deltas[1][0]; + dx2 = deltas[2][0]; + dx3 = deltas[3][0]; + + /* extract the y deltas */ + y = deltas[0][1]; + dy = deltas[1][1]; + dy2 = deltas[2][1]; + dy3 = deltas[3][1]; + + index = 1; + + /* loop over the curve */ + for (i = 0; i < subdivisions; i++) + { + /* increment the x values */ + x += dx; + dx += dx2; + dx2 += dx3; + + /* increment the y values */ + y += dy; + dy += dy2; + dy2 += dy3; + +/* printf("x = %g, y = %g\n",x,y); */ + + /* if this point is different than the last one...then draw it */ + /* Note : + * It assumes the udata is the place we want the + * floating version of the coords to be stuffed. + * These are needed when we calculate the gradient of the + * curve. + */ + + if(!bdist->firstpnt) + { + gdouble rx = x; + gdouble ry = y; + gdouble dx = bdist->lastx - rx; + gdouble dy = bdist->lasty - ry; + + bdist->curdist += sqrt((dx*dx)+(dy*dy)); + if(bdist->curdist >= bdist->dist) + { + *(bdist->x) = (gint)ROUND((rx + dx/2)); + *(bdist->y) = (gint)ROUND((ry + dy/2)); + if(dx == 0.0) + *(bdist->gradient) = G_MAXDOUBLE; + else + *(bdist->gradient) = dy/dx; + +/* printf("found x = %d, y = %d\n",*(bdist->x),*(bdist->y)); */ + bdist->found = TRUE; + break; + } + bdist->lastx = rx; + bdist->lasty = ry; + } + else + { + bdist->firstpnt = FALSE; + bdist->lastx = x; + bdist->lasty = y; + } + } +} + +static void +bezier_draw_curve_for_distance (BezierSelect *bezier_sel, + BezierDistance *udata) +{ + BezierPoint * points; + BezierPoint * start_pt; + int num_points; + + points = bezier_sel->points; + + if (bezier_sel->closed) + { + start_pt = bezier_sel->points; + + do { + bezier_draw_segment_for_distance (bezier_sel, points, + SUBDIVIDE, + udata); + + points = points->next; + points = points->next; + points = points->next; + } while (points != start_pt); + } + else + { + num_points = bezier_sel->num_points; + + while (num_points >= 4) + { + bezier_draw_segment_for_distance (bezier_sel, points, + SUBDIVIDE, + udata); + points = points->next; + points = points->next; + points = points->next; + num_points -= 3; + } + } +} + +gint +bezier_distance_along(BezierSelect *bezier_sel, + int open_path, + gdouble dist, + gint *x, + gint *y, + gdouble *gradient) +{ + /* Render the curve as points then walk along it... */ + BezierDistance *bdist = g_new0(BezierDistance,1); + gint ret; + + bdist->firstpnt = TRUE; + bdist->curdist = 0.0; + bdist->lastx = 0.0; + bdist->lasty = 0.0; + bdist->dist = dist; + bdist->x = x; + bdist->y = y; + bdist->gradient = gradient; + bdist->found = FALSE; + + bezier_draw_curve_for_distance (bezier_sel,bdist); + ret = bdist->found; + + g_free(bdist); + return (ret); } diff --git a/app/tools/bezier_selectP.h b/app/tools/bezier_selectP.h index 2ddd362d92..e472fda84e 100644 --- a/app/tools/bezier_selectP.h +++ b/app/tools/bezier_selectP.h @@ -63,17 +63,17 @@ struct _bezier_select GSList **scanlines; /* used in converting a curve */ }; -typedef void (*BezierPointsFunc) (BezierSelect *, GdkPoint *, int); +typedef void (*BezierPointsFunc) (BezierSelect *, GdkPoint *, int,gpointer); /* Functions */ int bezier_select_load (void *, BezierPoint *, int, int); -void bezier_draw_curve (BezierSelect *,BezierPointsFunc, int); +void bezier_draw_curve (BezierSelect *,BezierPointsFunc, int,gpointer); void bezier_select_reset (BezierSelect *); void bezier_add_point (BezierSelect *, int, int, int); void bezier_paste_bezierselect_to_current (GDisplay *,BezierSelect *); void bezier_select_mode (gint); void bezier_stroke (BezierSelect *, GDisplay *, int, int); void bezier_to_selection (BezierSelect *, GDisplay *); - +gint bezier_distance_along (BezierSelect *, gint, gdouble,gint *,gint *,gdouble *); #endif /* __BEZIER_SELECTP_H__ */ diff --git a/app/tools/gimpmovetool.c b/app/tools/gimpmovetool.c index 4a8936df32..743a5f890c 100644 --- a/app/tools/gimpmovetool.c +++ b/app/tools/gimpmovetool.c @@ -262,6 +262,12 @@ move_tool_motion (Tool *tool, if (private->guide) { move_draw_guide (gdisp, private->guide); + + if(mevent && mevent->window != gdisp->canvas->window) + { + private->guide->position = -1; + return; + } if (mevent) { diff --git a/app/tools/move.c b/app/tools/move.c index 4a8936df32..743a5f890c 100644 --- a/app/tools/move.c +++ b/app/tools/move.c @@ -262,6 +262,12 @@ move_tool_motion (Tool *tool, if (private->guide) { move_draw_guide (gdisp, private->guide); + + if(mevent && mevent->window != gdisp->canvas->window) + { + private->guide->position = -1; + return; + } if (mevent) { diff --git a/app/xcf.c b/app/xcf.c index f30ef6722b..315d4f9eff 100644 --- a/app/xcf.c +++ b/app/xcf.c @@ -777,13 +777,14 @@ static void write_one_path(gpointer pptr, gpointer iptr) info->cp += xcf_write_int32(info->fp, &closed,1); num_points = g_slist_length(bzp->path_details); info->cp += xcf_write_int32(info->fp, &num_points,1); - version = 2; + version = 3; info->cp += xcf_write_int32(info->fp, &version,1); info->cp += xcf_write_int32(info->fp, &bzp->pathtype,1); + info->cp += xcf_write_int32(info->fp, &bzp->tattoo,1); g_slist_foreach(bzp->path_details,write_bz_point,info); } -static PATHP read_one_path(XcfInfo *info) +static PATHP read_one_path(GImage *gimage,XcfInfo *info) { PATHP bzp; gchar *name; @@ -792,6 +793,7 @@ static PATHP read_one_path(XcfInfo *info) guint32 closed; guint32 num_points; guint32 version; /* changed from num_paths */ + Tattoo tattoo = 0; GSList *pts_list = NULL; PathType ptype; @@ -825,12 +827,25 @@ static PATHP read_one_path(XcfInfo *info) pts_list = g_slist_append(pts_list,bpt); } } + else if(version == 3) + { + /* Has extra tatto field */ + info->cp += xcf_read_int32(info->fp, (guint32 *)&ptype,1); + info->cp += xcf_read_int32(info->fp, (guint32 *)&tattoo,1); + while(num_points-- > 0) + { + PATHPOINTP bpt; + /* Read in a path */ + bpt = read_bz_point(info); + pts_list = g_slist_append(pts_list,bpt); + } + } else { g_warning("Unknown path type..Possibly corrupt XCF file"); } - bzp = path_new(ptype,pts_list,closed,(gint)state,locked,name); + bzp = path_new(gimage,ptype,pts_list,closed,(gint)state,locked,tattoo,name); return(bzp); } @@ -866,7 +881,7 @@ static PathsList * read_bzpaths(GImage *gimage, XcfInfo *info) { PATHP bzp; /* Read in a path */ - bzp = read_one_path(info); + bzp = read_one_path(gimage,info); bzp_list = g_slist_append(bzp_list,bzp); } diff --git a/app/xcf/xcf.c b/app/xcf/xcf.c index f30ef6722b..315d4f9eff 100644 --- a/app/xcf/xcf.c +++ b/app/xcf/xcf.c @@ -777,13 +777,14 @@ static void write_one_path(gpointer pptr, gpointer iptr) info->cp += xcf_write_int32(info->fp, &closed,1); num_points = g_slist_length(bzp->path_details); info->cp += xcf_write_int32(info->fp, &num_points,1); - version = 2; + version = 3; info->cp += xcf_write_int32(info->fp, &version,1); info->cp += xcf_write_int32(info->fp, &bzp->pathtype,1); + info->cp += xcf_write_int32(info->fp, &bzp->tattoo,1); g_slist_foreach(bzp->path_details,write_bz_point,info); } -static PATHP read_one_path(XcfInfo *info) +static PATHP read_one_path(GImage *gimage,XcfInfo *info) { PATHP bzp; gchar *name; @@ -792,6 +793,7 @@ static PATHP read_one_path(XcfInfo *info) guint32 closed; guint32 num_points; guint32 version; /* changed from num_paths */ + Tattoo tattoo = 0; GSList *pts_list = NULL; PathType ptype; @@ -825,12 +827,25 @@ static PATHP read_one_path(XcfInfo *info) pts_list = g_slist_append(pts_list,bpt); } } + else if(version == 3) + { + /* Has extra tatto field */ + info->cp += xcf_read_int32(info->fp, (guint32 *)&ptype,1); + info->cp += xcf_read_int32(info->fp, (guint32 *)&tattoo,1); + while(num_points-- > 0) + { + PATHPOINTP bpt; + /* Read in a path */ + bpt = read_bz_point(info); + pts_list = g_slist_append(pts_list,bpt); + } + } else { g_warning("Unknown path type..Possibly corrupt XCF file"); } - bzp = path_new(ptype,pts_list,closed,(gint)state,locked,name); + bzp = path_new(gimage,ptype,pts_list,closed,(gint)state,locked,tattoo,name); return(bzp); } @@ -866,7 +881,7 @@ static PathsList * read_bzpaths(GImage *gimage, XcfInfo *info) { PATHP bzp; /* Read in a path */ - bzp = read_one_path(info); + bzp = read_one_path(gimage,info); bzp_list = g_slist_append(bzp_list,bzp); } diff --git a/tools/pdbgen/pdb/paths.pdb b/tools/pdbgen/pdb/paths.pdb index 5da3c02fd6..dbe1ba0877 100644 --- a/tools/pdbgen/pdb/paths.pdb +++ b/tools/pdbgen/pdb/paths.pdb @@ -316,10 +316,182 @@ CODE ); } +sub path_get_point_at_dist { + $blurb = 'Get point on a path at a specified distance along the path'; + + $help = <<'HELP'; +This will return the x,y position of a point at a given distance along the +bezier curve. The distance will the obtained by first digitizing the +curve internally an then walking along the curve. For a closed curve the +start of the path is the first point on the path that was created. This might +not be obvious. Note the current path is used. +HELP + + &pdb_misc; + + @inargs = ( &std_image_arg, + { name => 'distance', + type => 'float', + desc => 'The distance along the path' + } + ); + $inargs[0]->{desc} = 'The ID of the image the paths belongs to'; + + @outargs = ( + { name => 'x_point', + init => 1, + type => 'int32', + desc => 'The x position of the point' + }, + { name => 'y_point', + type => 'int32', + desc => 'The y position of the point', + init => 1 + }, + { name => 'gradient', + type => 'float', + desc => 'The gradient at the specified point', + init => 1 + } + ); + + %invoke = ( + code => <<'CODE' +{ + /* Get the path with the given name */ + PathsList *plist = gimage->paths; + + if(plist && plist->bz_paths) + { + PATHP pptr = NULL; + + if(plist->last_selected_row >= 0) + { + pptr = (PATHP)g_slist_nth_data(plist->bz_paths,plist->last_selected_row); + success = paths_distance(pptr,distance,&x_point,&y_point,&gradient); + } + else + { + success = FALSE; + } + } + else + { + success = FALSE; + } +} +CODE + ); +} + +sub path_get_tattoo { + $blurb = 'Returns the tattoo associated with the name path'; + + $help = <<'HELP'; +This procedure returns the tattoo associated with the specified path. A tattoo is a unique and permenant identifier attached to a path that can be used to uniquely identify a path within an image even between sessions. +HELP + + &pdb_misc; + + @inargs = ( + &std_image_arg, + { name => 'pathname', type => 'string', + desc => 'the name of the path whose tattoo should be obtained', + alias => 'pname' } + ); + $inargs[0]->{desc} = 'The ID of the image'; + + @outargs = ( + { name => 'tattoo', + type => 'int32', + init => 1, + desc => 'The tattoo associated with the name path', + }, + ); + + %invoke = ( + vars => [ 'PathsList *plist' ], + code => <<'CODE' +{ + PATHP pptr = NULL; + /* Get the path with the given name */ + plist = gimage->paths; + + if (plist && plist->bz_paths) + { + GSList *pl = plist->bz_paths; + + while (pl) + { + pptr = pl->data; + + if (strcmp (pname, pptr->name->str) == 0) + break; /* Found the path */ + + pl = pl->next; + pptr = NULL; + } + + if (pl && pptr) + { + tattoo = paths_get_tattoo(pptr); + } + else + success = FALSE; + } +} +CODE + ); +} + +sub get_path_by_tattoo { + $blurb = 'Return the name of the path with the given tattoo'; + + $help = <<'HELP'; +The procedure returns the name of the path in the specified image which has the passed tattoo. The tattoos are unique within the image and will be preserved across sessions and through renaming of the path. An error is returned if no path woth the specified tattoo can be found. +HELP + + &pdb_misc; + @inargs = ( + &std_image_arg, + { name => 'tattoo', type => 'int32', + desc => 'The tattoo of the required path', + } + ); + + $inargs[0]->{desc} = 'The ID of the image'; + + @outargs = ( + { name => 'path_name', type => 'string', + desc => 'The name of the path with the specified tattoo', + alias => 'g_strdup (pptr->name->str)', no_declare => 1 } + ); + + %invoke = ( + vars => [ 'PathsList *plist', 'PATHP pptr = NULL' ], + code => <<'CODE' +{ + /* Get the path with the given name */ + plist = gimage->paths; + + if (plist && plist->bz_paths) + { + if((pptr = paths_get_path_by_tattoo(gimage,tattoo)) == NULL) + success = FALSE; + } + else + success = FALSE; +} +CODE + ); +} + + @headers = qw("gimage.h" "pathsP.h"); @procs = qw(path_list path_get_points path_get_current path_set_current - path_set_points path_stroke_current); + path_set_points path_stroke_current path_get_point_at_dist + path_get_tattoo get_path_by_tattoo); %exports = (app => [@procs]); $desc = 'Paths';