home *** CD-ROM | disk | FTP | other *** search
- /* The GIMP -- an image manipulation program
- *
- * This file Copyright (C) 1999 Simon Budig
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
- /*
- * Complete new path-tool by Simon Budig <Simon.Budig@unix-ag.org>
- *
- * a path manipulation core independent of the underlying formula:
- * implement bezier-curves, intelligent scissors-curves, splines...
- *
- * A Path is a collection of curves, which are constructed from
- * segments between two anchors.
- */
-
- #include <math.h>
- /* #include "appenv.h"
- */
-
- #include "draw_core.h"
- #include "cursorutil.h"
- #include "path_tool.h"
- #include "path_toolP.h"
- #include "path_curves.h"
-
- #include "config.h"
- #include "libgimp/gimpintl.h"
-
- /*
- * Every new curve-type has to have a parameter between 0 and 1, and
- * should go from a starting to a target point.
- */
-
-
-
- /* Some defines... */
-
- #define PATH_TOOL_WIDTH 8
- #define PATH_TOOL_HALFWIDTH 4
-
- /* local function prototypes */
-
-
- /* Small functions to determine coordinates, iterate over path/curve/segment */
-
- void path_segment_get_coordinates (PathSegment *,
- gdouble,
- gint *,
- gint *);
- void path_traverse_path (Path *,
- PathTraverseFunc,
- CurveTraverseFunc,
- SegmentTraverseFunc,
- gpointer);
- void path_traverse_curve (Path *,
- PathCurve *,
- CurveTraverseFunc,
- SegmentTraverseFunc,
- gpointer);
- void path_traverse_segment (Path *,
- PathCurve *,
- PathSegment *,
- SegmentTraverseFunc,
- gpointer);
- gdouble path_locate_point (Path *,
- PathCurve **,
- PathSegment **,
- gint,
- gint,
- gint,
- gint,
- gint);
-
- /* Tools to manipulate paths, curves, segments */
-
- PathCurve * path_add_curve (Path *,
- gint,
- gint);
- PathSegment * path_append_segment (Path *,
- PathCurve *,
- SegmentType,
- gint,
- gint);
- PathSegment * path_prepend_segment (Path *,
- PathCurve *,
- SegmentType,
- gint,
- gint);
- PathSegment * path_split_segment (PathSegment *,
- gdouble);
- void path_join_curves (PathSegment *,
- PathSegment *);
- void path_flip_curve (PathCurve *);
- void path_free_path (Path *);
- void path_free_curve (PathCurve *);
- void path_free_segment (PathSegment *);
- void path_delete_segment (PathSegment *);
- void path_print (Path *);
- void path_offset_active (Path *, gdouble, gdouble);
- void path_set_flags (PathTool *,
- Path *,
- PathCurve *,
- PathSegment *,
- guint32,
- guint32);
-
- /* High level image-manipulation functions */
-
- void path_stroke (PathTool *,
- Path *);
- void path_to_selection (PathTool *,
- Path *);
-
- /* Functions necessary for the tool */
-
- void path_tool_button_press (Tool *, GdkEventButton *, gpointer);
- void path_tool_button_release (Tool *, GdkEventButton *, gpointer);
- void path_tool_motion (Tool *, GdkEventMotion *, gpointer);
- void path_tool_cursor_update (Tool *, GdkEventMotion *, gpointer);
- void path_tool_control (Tool *, ToolAction, gpointer);
- void path_tool_draw (Tool *);
- void path_tool_draw_curve (Tool *, PathCurve *);
- void path_tool_draw_segment (Tool *, PathSegment *);
-
- gdouble path_tool_on_curve (Tool *, gint, gint, gint,
- Path**, PathCurve**, PathSegment**);
- gboolean path_tool_on_anchors (Tool *, gint, gint, gint,
- Path**, PathCurve**, PathSegment**);
- gint path_tool_on_handles (Tool *, gint, gint, gint,
- Path **, PathCurve **, PathSegment **);
-
- gint path_tool_button_press_canvas (Tool *, GdkEventButton *, GDisplay *);
- gint path_tool_button_press_anchor (Tool *, GdkEventButton *, GDisplay *);
- gint path_tool_button_press_handle (Tool *, GdkEventButton *, GDisplay *);
- gint path_tool_button_press_curve (Tool *, GdkEventButton *, GDisplay *);
- void path_tool_motion_anchor (Tool *, GdkEventMotion *, GDisplay *);
- void path_tool_motion_handle (Tool *, GdkEventMotion *, GDisplay *);
- void path_tool_motion_curve (Tool *, GdkEventMotion *, GDisplay *);
-
-
- /* the path tool options */
- static ToolOptions *path_options = NULL;
-
-
- /*
- *
- *
- * Here we go!
- *
- *
- */
-
- /*
- * These functions are for applying a function over a complete
- * path/curve/segment. They can pass information to each other
- * with a arbitrary data structure
- *
- * The idea behind the three different functions is:
- * if pathfunc != NULL
- * call pathfunc for every curve
- * else
- * if curvefunc != NULL
- * call curvefunc for every segment
- * else
- * call segmentfunc for every point
- *
- */
-
- void
- path_traverse_path (Path *path,
- PathTraverseFunc pathfunc,
- CurveTraverseFunc curvefunc,
- SegmentTraverseFunc segmentfunc,
- gpointer data)
- {
- PathCurve *cur_curve;
-
- if (path && path->curves)
- {
- cur_curve = path->curves;
- if (pathfunc)
- do {
- (* pathfunc) (path, cur_curve, data);
- cur_curve = cur_curve->next;
- } while (cur_curve && cur_curve != path->curves);
- else
- do {
- path_traverse_curve (path, cur_curve, curvefunc, segmentfunc, data);
- cur_curve = cur_curve->next;
- } while (cur_curve && cur_curve != path->curves);
- }
- }
-
-
- void
- path_traverse_curve (Path *path,
- PathCurve *curve,
- CurveTraverseFunc curvefunc,
- SegmentTraverseFunc segmentfunc,
- gpointer data)
- {
- PathSegment *cur_segment;
-
- if (curve && curve->segments)
- {
- cur_segment = curve->segments;
- if (curvefunc)
- do {
- (* curvefunc) (path, curve, cur_segment, data);
- cur_segment = cur_segment->next;
- } while (cur_segment && cur_segment != curve->segments);
- else
- do {
- path_traverse_segment (path, curve, cur_segment, segmentfunc, data);
- cur_segment = cur_segment->next;
- } while (cur_segment && cur_segment != curve->segments);
- }
- }
-
- void
- path_traverse_segment (Path *path,
- PathCurve *curve,
- PathSegment *segment,
- SegmentTraverseFunc function,
- gpointer data)
- {
- #ifdef PATH_TOOL_DEBUG
- fprintf(stderr, "path_traverse_segment\n");
- #endif PATH_TOOL_DEBUG
-
- /* XXX: here we need path_curve_get_point(s) */
-
- /* Something like:
- * for i = 1 to subsamples {
- * (x,y) = get_coordinates(i / subsamples)
- * (* function) (....)
- * }
- */
- }
-
- /**************************************************************
- * Helper functions for manipulating the data-structures:
- */
-
- PathCurve *
- path_add_curve (Path * cur_path,
- gint x,
- gint y)
- {
- PathCurve * tmp = cur_path->curves;
- PathCurve * new_curve = NULL;
-
- #ifdef PATH_TOOL_DEBUG
- fprintf(stderr, "path_add_curve\n");
- #endif PATH_TOOL_DEBUG
-
- if (cur_path) {
- new_curve = g_new (PathCurve, 1);
-
- new_curve->parent = cur_path;
- new_curve->next = tmp;
- new_curve->prev = NULL;
- new_curve->cur_segment = NULL;
- new_curve->segments = NULL;
-
- if (tmp) tmp->prev = new_curve;
-
- cur_path->curves = cur_path->cur_curve = new_curve;
-
- new_curve->segments = path_prepend_segment (cur_path, new_curve, SEGMENT_BEZIER, x, y);
- }
- #ifdef PATH_TOOL_DEBUG
- else
- fprintf (stderr, "Fatal Error: path_add_curve called without valid path\n");
- #endif PATH_TOOL_DEBUG
-
- return new_curve;
- }
-
-
- PathSegment *
- path_append_segment (Path * cur_path,
- PathCurve * cur_curve,
- SegmentType type,
- gint x,
- gint y)
- {
- PathSegment * tmp = cur_curve->segments;
- PathSegment * new_segment = NULL;
-
- #ifdef PATH_TOOL_DEBUG
- fprintf(stderr, "path_append_segment\n");
- #endif PATH_TOOL_DEBUG
-
- if (cur_curve) {
- tmp = cur_curve->segments;
- while (tmp && tmp->next && tmp->next != cur_curve->segments) {
- tmp = tmp->next;
- }
-
- if (tmp == NULL || tmp->next == NULL) {
- new_segment = g_new (PathSegment, 1);
-
- new_segment->type = type;
- new_segment->x = x;
- new_segment->y = y;
- new_segment->flags = 0;
- new_segment->parent = cur_curve;
- new_segment->next = NULL;
- new_segment->prev = tmp;
- new_segment->data = NULL;
-
- if (tmp)
- tmp->next = new_segment;
-
- cur_curve->cur_segment = new_segment;
-
- path_curve_init_segment (new_segment);
-
- }
- #ifdef PATH_TOOL_DEBUG
- else
- fprintf(stderr, "Fatal Error: path_append_segment called with a closed curve\n");
- #endif PATH_TOOL_DEBUG
- }
- #ifdef PATH_TOOL_DEBUG
- else
- fprintf(stderr, "Fatal Error: path_append_segment called without valid curve\n");
- #endif PATH_TOOL_DEBUG
-
- return new_segment;
- }
-
-
- PathSegment *
- path_prepend_segment (Path * cur_path,
- PathCurve * cur_curve,
- SegmentType type,
- gint x,
- gint y)
- {
- PathSegment * tmp = cur_curve->segments;
- PathSegment * new_segment = NULL;
-
- #ifdef PATH_TOOL_DEBUG
- fprintf(stderr, "path_prepend_segment\n");
- #endif PATH_TOOL_DEBUG
-
- if (cur_curve) {
- tmp = cur_curve->segments;
-
- if (tmp == NULL || tmp->prev == NULL) {
- new_segment = g_new (PathSegment, 1);
-
- new_segment->type = type;
- new_segment->x = x;
- new_segment->y = y;
- new_segment->flags = 0;
- new_segment->parent = cur_curve;
- new_segment->next = tmp;
- new_segment->prev = NULL;
- new_segment->data = NULL;
-
- if (tmp)
- tmp->prev = new_segment;
-
- cur_curve->segments = new_segment;
- cur_curve->cur_segment = new_segment;
-
- path_curve_init_segment (new_segment);
- }
- #ifdef PATH_TOOL_DEBUG
- else
- fprintf(stderr, "Fatal Error: path_prepend_segment called with a closed curve\n");
- #endif PATH_TOOL_DEBUG
- }
- #ifdef PATH_TOOL_DEBUG
- else
- fprintf(stderr, "Fatal Error: path_prepend_segment called without valid curve\n");
- #endif PATH_TOOL_DEBUG
-
- return new_segment;
- }
-
- PathSegment *
- path_split_segment (PathSegment *segment,
- gdouble position)
- {
- PathSegment * new_segment = NULL;
-
- #ifdef PATH_TOOL_DEBUG
- fprintf(stderr, "path_split_segment\n");
- #endif PATH_TOOL_DEBUG
- if (segment && segment->next) {
- new_segment = g_new (PathSegment, 1);
-
- new_segment->type = segment->type;
- /* XXX: Giving PathTool as NULL Pointer! */
- path_curve_get_point (NULL, segment, position, &(new_segment->x), &(new_segment->y));
- new_segment->flags = 0;
- new_segment->parent = segment->parent;
- new_segment->next = segment->next;
- new_segment->prev = segment;
- new_segment->data = NULL;
-
- path_curve_init_segment (new_segment);
-
- new_segment->next->prev = new_segment;
- segment->next = new_segment;
-
- return new_segment;
-
- }
- #ifdef PATH_TOOL_DEBUG
- else
- fprintf(stderr, "path_split_segment without valid segment\n");
- #endif PATH_TOOL_DEBUG
- return NULL;
-
- }
-
- /*
- * Join two arbitrary endpoints and free the parent from the second
- * segment, if it differs from the first parents.
- */
-
- void
- path_join_curves (PathSegment *segment1,
- PathSegment *segment2)
- {
- PathCurve *curve1, *curve2;
- PathSegment *tmp;
-
- if ((segment1->next && segment1->prev) || (segment2->next && segment2->prev)) {
- #ifdef PATH_TOOL_DEBUG
- fprintf(stderr, "Fatal Error: path_join_curves called with a closed segment\n");
- #endif PATH_TOOL_DEBUG
- return;
- }
- if (segment1->parent == segment2->parent) {
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "Joining beginning and end of the same curve...\n");
- #endif PATH_TOOL_DEBUG
- if (segment2->next == NULL) {
- segment2->next = segment1;
- segment1->prev = segment2;
- } else {
- segment2->prev = segment1;
- segment1->next = segment2;
- }
- /* XXX: Probably some segment-updates needed */
- return;
- }
-
- if (segment1->next == NULL && segment2->next == NULL) {
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "Flipping second curve (next, next)...\n");
- #endif PATH_TOOL_DEBUG
- path_flip_curve (segment2->parent);
- /* segment2 = segment2->parent->segments;
- */
- }
-
- if (segment1->prev == NULL && segment2->prev == NULL) {
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "Flipping second curve (prev, prev)...\n");
- #endif PATH_TOOL_DEBUG
- path_flip_curve (segment2->parent);
- /* segment2 = segment2->parent->segments;
- * while (segment2->next)
- * segment2 = segment2->next;
- */
- }
-
- if (segment1->next == NULL && segment2->prev == NULL) {
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "Appending second to first curve...\n");
- #endif PATH_TOOL_DEBUG
- curve1 = segment1->parent;
- curve2 = segment2->parent;
-
- segment1->next = segment2;
- segment2->prev = segment1;
-
- curve2->segments = NULL;
-
- if (curve2->prev)
- curve2->prev->next = curve2->next;
- if (curve2->next)
- curve2->next->prev = curve2->prev;
-
- if (curve2->parent->curves == curve2)
- curve2->parent->curves = curve2->next;
-
- path_free_curve (curve2);
-
- tmp = segment2;
-
- while (tmp) {
- tmp->parent = curve1;
- tmp = tmp->next;
- }
- /* XXX: Probably some segment-updates needed */
- return;
- }
-
- if (segment1->prev == NULL && segment2->next == NULL) {
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "Prepending second to first curve...\n");
- #endif PATH_TOOL_DEBUG
- curve1 = segment1->parent;
- curve2 = segment2->parent;
-
- segment1->prev = segment2;
- segment2->next = segment1;
-
- curve2->segments = NULL;
- if (curve2->prev)
- curve2->prev->next = curve2->next;
- if (curve2->next)
- curve2->next->prev = curve2->prev;
- if (curve2->parent->curves == curve2)
- curve2->parent->curves = curve2->next;
- path_free_curve (curve2);
-
- tmp = segment2;
-
- while (tmp) {
- tmp->parent = curve1;
- curve1->segments = tmp;
- tmp = tmp->prev;
- }
- return;
- /* XXX: Probably some segment-updates needed */
- }
-
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "Cant join these curves yet...\nThis should not happen.");
- return;
- #endif PATH_TOOL_DEBUG
-
- }
-
- /*
- * This function reverses the order of the anchors. This is
- * necessary for some joining operations.
- */
- void
- path_flip_curve (PathCurve *curve)
- {
- gpointer *end_data;
- SegmentType end_type;
-
- PathSegment *tmp, *tmp2;
-
- if (!curve && !curve->segments) {
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "path_flip_curve: No curve o no segments to flip!\n");
- #endif PATH_TOOL_DEBUG
- return;
- }
-
- tmp = curve->segments;
-
- while (tmp->next)
- tmp = tmp->next;
-
- end_data = tmp->data;
- end_type = tmp->type;
-
- tmp->parent->segments = tmp;
-
- while (tmp) {
- tmp2 = tmp->next;
- tmp->next = tmp->prev;
- tmp->prev = tmp2;
- if (tmp->next) {
- tmp->type = tmp->next->type;
- tmp->data = tmp->next->data;
- } else {
- tmp->type = end_type;
- tmp->data = end_data;
- }
- path_curve_flip_segment (tmp);
- tmp = tmp->next;
- }
- }
-
-
- void
- path_free_path (Path * path)
- {
- PathCurve *tmp1, *tmp2;
-
- if (path)
- {
- tmp2 = path->curves;
-
- while ((tmp1 = tmp2) != NULL)
- {
- tmp2 = tmp1->next;
- path_free_curve (tmp1);
- }
- g_string_free(path->name, TRUE);
- g_free(path);
- }
- }
-
- void
- path_free_curve (PathCurve *curve)
- {
- PathSegment *tmp1, *tmp2;
-
- if (curve)
- {
- tmp2 = curve->segments;
-
- /* break closed curves */
- if (tmp2 && tmp2->prev)
- tmp2->prev->next = NULL;
-
- while ((tmp1 = tmp2) != NULL)
- {
- tmp2 = tmp1->next;
- path_free_segment (tmp1);
- }
- g_free(curve);
- }
- }
-
- void
- path_free_segment (PathSegment *segment)
- {
- if (segment)
- {
- /* Clear the active flag to keep path_tool->single_active_segment
- * consistent */
-
-
- path_set_flags (segment->parent->parent->path_tool, segment->parent->parent,
- segment->parent, segment, 0, SEGMENT_ACTIVE);
-
- path_curve_cleanup_segment(segment);
-
- g_free (segment);
- }
- }
-
- void
- path_delete_curve (PathCurve *curve)
- {
- if (curve)
- {
- if (curve->next)
- curve->next->prev = curve->prev;
- if (curve->prev)
- curve->prev->next = curve->next;
-
- if (curve == curve->parent->curves) {
- curve->parent->curves = curve->next;
- }
-
- path_free_curve (curve);
- }
- }
-
- void
- path_delete_segment (PathSegment *segment)
- {
- if (segment)
- {
- if (segment->next)
- segment->next->prev = segment->prev;
- if (segment->prev)
- segment->prev->next = segment->next;
-
- /* If the remaining curve is closed and has a
- * single point only, open it.
- */
- if (segment->next == segment->prev && segment->next)
- segment->next->next = segment->next->prev = NULL;
-
- if (segment == segment->parent->segments)
- segment->parent->segments = segment->next;
-
- if (segment->parent->segments == NULL)
- path_delete_curve (segment->parent);
-
- path_free_segment (segment);
-
- /*
- * here we have to update the surrounding segments
- */
- /* XXX: Please add path_curve_update_segment here */
- }
- }
-
-
- /*
- * A function to determine, which object is hit by the cursor
- */
-
- gint
- path_tool_cursor_position (Tool *tool,
- gint x,
- gint y,
- gint halfwidth,
- Path **pathP,
- PathCurve **curveP,
- PathSegment **segmentP,
- gdouble *positionP,
- gint *handle_idP)
- {
- gdouble pos;
- gint handle_id;
-
- if (path_tool_on_anchors (tool, x, y, halfwidth, pathP, curveP, segmentP))
- return ON_ANCHOR;
-
- handle_id = path_tool_on_handles (tool, x, y, halfwidth, pathP, curveP, segmentP);
- if (handle_id) {
- if (handle_idP) (*handle_idP) = handle_id;
- return ON_HANDLE;
- }
-
- pos = path_tool_on_curve (tool, x, y, halfwidth, pathP, curveP, segmentP);
- if (pos >= 0 && pos <= 1) {
- if (positionP) (*positionP) = pos;
- return ON_CURVE;
- }
-
-
- return ON_CANVAS;
- }
-
-
- /**************************************************************
- * The click-callbacks for the tool
- */
-
- void
- path_tool_button_press (Tool *tool,
- GdkEventButton *bevent,
- gpointer gdisp_ptr)
- {
- GDisplay * gdisp;
- PathTool * path_tool;
- gint grab_pointer=0;
- gint x, y, halfwidth, dummy;
-
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "path_tool_button_press\n");
- #endif PATH_TOOL_DEBUG
-
- gdisp = (GDisplay *) gdisp_ptr;
- path_tool = (PathTool *) tool->private;
- tool->gdisp_ptr = gdisp_ptr;
-
- /* Transform window-coordinates to canvas-coordinates */
- gdisplay_untransform_coords (gdisp, bevent->x, bevent->y, &x, &y, TRUE, 0);
- #ifdef PATH_TOOL_DEBUG
- fprintf(stderr, "Clickcoordinates %d, %d\n",x,y);
- #endif PATH_TOOL_DEBUG
- path_tool->click_x = x;
- path_tool->click_y = y;
- path_tool->click_modifier = bevent->state;
- /* get halfwidth in image coord */
- gdisplay_untransform_coords (gdisp, bevent->x + PATH_TOOL_HALFWIDTH, 0, &halfwidth, &dummy, TRUE, 0);
- halfwidth -= x;
- path_tool->click_halfwidth = halfwidth;
-
- if (!path_tool->cur_path->curves)
- draw_core_start (path_tool->core, gdisp->canvas->window, tool);
-
- /* determine point, where clicked,
- * switch accordingly.
- */
-
- path_tool->click_type = path_tool_cursor_position (tool, x, y, halfwidth,
- &(path_tool->click_path),
- &(path_tool->click_curve),
- &(path_tool->click_segment),
- &(path_tool->click_position),
- &(path_tool->click_handle_id));
-
- switch (path_tool->click_type)
- {
- case ON_CANVAS:
- grab_pointer = path_tool_button_press_canvas(tool, bevent, gdisp);
- break;
-
- case ON_ANCHOR:
- grab_pointer = path_tool_button_press_anchor(tool, bevent, gdisp);
- break;
-
- case ON_HANDLE:
- grab_pointer = path_tool_button_press_handle(tool, bevent, gdisp);
- break;
-
- case ON_CURVE:
- grab_pointer = path_tool_button_press_curve(tool, bevent, gdisp);
- break;
-
- default:
- g_message("Huh? Whats happening here? (button_press_*)");
- }
-
- if (grab_pointer)
- gdk_pointer_grab (gdisp->canvas->window, FALSE,
- GDK_POINTER_MOTION_HINT_MASK |
- GDK_BUTTON1_MOTION_MASK |
- GDK_BUTTON_RELEASE_MASK,
- NULL, NULL, bevent->time);
-
- tool->state = ACTIVE;
-
- }
-
- gint
- path_tool_button_press_anchor (Tool *tool,
- GdkEventButton *bevent,
- GDisplay *gdisp)
- {
- static guint32 last_click_time=0;
- gboolean doubleclick=FALSE;
- PathTool *path_tool = tool->private;
-
- Path * cur_path = path_tool->cur_path;
- PathSegment *p_sas;
- gint grab_pointer;
-
- #ifdef PATH_TOOL_DEBUG
- fprintf(stderr, "path_tool_button_press_anchor:\n");
- #endif PATH_TOOL_DEBUG
-
- grab_pointer = 1;
-
- if (!cur_path) {
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "Fatal error: No current Path\n");
- #endif PATH_TOOL_DEBUG
- return 0;
- }
-
- /*
- * We have to determine, if this was a doubleclick for ourself, because
- * disp_callback.c ignores the GDK_[23]BUTTON_EVENT's and adding them to
- * the switch statement confuses some tools.
- */
- if (bevent->time - last_click_time < 250) {
- doubleclick=TRUE;
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "Doppelclick!\n");
- #endif PATH_TOOL_DEBUG
- } else
- doubleclick=FALSE;
- last_click_time = bevent->time;
-
-
- draw_core_pause (path_tool->core, tool);
-
- /* The user pressed on an anchor:
- * normally this activates this anchor
- * + SHIFT toggles the activity of an anchor.
- * if this anchor is at the end of an open curve and the other
- * end is active, close the curve.
- *
- * Doubleclick (de)activates the whole curve (not Path!).
- */
-
- p_sas = path_tool->single_active_segment;
-
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "p_sas: %p\n", p_sas);
- #endif PATH_TOOL_DEBUG
-
- if (path_tool->click_modifier & GDK_SHIFT_MASK) {
- if (path_tool->active_count == 1 && p_sas && p_sas != path_tool->click_segment &&
- (p_sas->next == NULL || p_sas->prev == NULL) &&
- (path_tool->click_segment->next == NULL || path_tool->click_segment->prev == NULL)) {
- /*
- * if this is the end of an open curve and the single active segment was another
- * open end, connect those ends.
- */
- path_join_curves (path_tool->click_segment, p_sas);
- path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
- NULL, 0, SEGMENT_ACTIVE);
- }
-
- if (doubleclick)
- /*
- * Doubleclick set the whole curve to the same state, depending on the
- * state of the clicked anchor.
- */
- if (path_tool->click_segment->flags & SEGMENT_ACTIVE)
- path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
- NULL, SEGMENT_ACTIVE, 0);
- else
- path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
- NULL, 0, SEGMENT_ACTIVE);
- else
- /*
- * Toggle the state of the clicked anchor.
- */
- if (path_tool->click_segment->flags & SEGMENT_ACTIVE)
- path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
- path_tool->click_segment, 0, SEGMENT_ACTIVE);
- else
- path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
- path_tool->click_segment, SEGMENT_ACTIVE, 0);
- }
- /*
- * Delete anchors, when CONTROL is pressed
- */
- else if (path_tool->click_modifier & GDK_CONTROL_MASK)
- {
- if (path_tool->click_segment->flags & SEGMENT_ACTIVE)
- {
- if (path_tool->click_segment->prev)
- path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
- path_tool->click_segment->prev, SEGMENT_ACTIVE, 0);
- else if (path_tool->click_segment->next)
- path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
- path_tool->click_segment->next, SEGMENT_ACTIVE, 0);
- }
-
- path_delete_segment (path_tool->click_segment);
- path_tool->click_segment = NULL;
- /* Maybe CTRL-ALT Click should remove the whole curve? Or the active points? */
- }
- else if (!(path_tool->click_segment->flags & SEGMENT_ACTIVE))
- {
- path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
- path_set_flags (path_tool, cur_path, path_tool->click_curve, path_tool->click_segment, SEGMENT_ACTIVE, 0);
- }
-
-
- draw_core_resume(path_tool->core, tool);
-
- return grab_pointer;
- }
-
-
- gint
- path_tool_button_press_handle (Tool *tool,
- GdkEventButton *bevent,
- GDisplay *gdisp)
- {
- static guint32 last_click_time=0;
- gboolean doubleclick=FALSE;
- PathTool *path_tool = tool->private;
-
- Path * cur_path = path_tool->cur_path;
- gint grab_pointer;
-
- #ifdef PATH_TOOL_DEBUG
- fprintf(stderr, "path_tool_button_press_handle:\n");
- #endif PATH_TOOL_DEBUG
-
- grab_pointer = 1;
-
- if (!cur_path) {
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "Fatal error: No current Path\n");
- #endif PATH_TOOL_DEBUG
- return 0;
- }
-
- /*
- * We have to determine, if this was a doubleclick for ourself, because
- * disp_callback.c ignores the GDK_[23]BUTTON_EVENT's and adding them to
- * the switch statement confuses some tools.
- */
- if (bevent->time - last_click_time < 250) {
- doubleclick=TRUE;
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "Doppelclick!\n");
- #endif PATH_TOOL_DEBUG
- } else
- doubleclick=FALSE;
- last_click_time = bevent->time;
-
- return grab_pointer;
- }
-
- gint
- path_tool_button_press_canvas (Tool *tool,
- GdkEventButton *bevent,
- GDisplay *gdisp)
- {
- PathTool *path_tool = tool->private;
-
- Path * cur_path = path_tool->cur_path;
- PathCurve * cur_curve;
- PathSegment * cur_segment;
- gint grab_pointer;
-
- #ifdef PATH_TOOL_DEBUG
- fprintf(stderr, "path_tool_button_press_canvas:\n");
- #endif PATH_TOOL_DEBUG
-
- grab_pointer = 1;
-
- if (!cur_path) {
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "Fatal error: No current Path\n");
- #endif PATH_TOOL_DEBUG
- return 0;
- }
-
- draw_core_pause (path_tool->core, tool);
-
- if (path_tool->active_count == 1 && path_tool->single_active_segment != NULL
- && (path_tool->single_active_segment->prev == NULL || path_tool->single_active_segment->next == NULL)) {
- cur_segment = path_tool->single_active_segment;
- cur_curve = cur_segment->parent;
-
- path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
-
- if (cur_segment->next == NULL)
- cur_curve->cur_segment = path_append_segment(cur_path, cur_curve, SEGMENT_BEZIER, path_tool->click_x, path_tool->click_y);
- else
- cur_curve->cur_segment = path_prepend_segment(cur_path, cur_curve, SEGMENT_BEZIER, path_tool->click_x, path_tool->click_y);
- if (cur_curve->cur_segment) {
- path_set_flags (path_tool, cur_path, cur_curve, cur_curve->cur_segment, SEGMENT_ACTIVE, 0);
- }
- } else {
- if (path_tool->active_count == 0) {
- path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
- cur_path->cur_curve = path_add_curve(cur_path, path_tool->click_x, path_tool->click_y);
- path_set_flags (path_tool, cur_path, cur_path->cur_curve, cur_path->cur_curve->segments, SEGMENT_ACTIVE, 0);
- } else {
- path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
- }
- }
-
- draw_core_resume(path_tool->core, tool);
-
- return 0;
- }
-
- gint
- path_tool_button_press_curve (Tool *tool,
- GdkEventButton *bevent,
- GDisplay *gdisp)
- {
- PathTool *path_tool = tool->private;
-
- Path * cur_path = path_tool->cur_path;
- PathSegment * cur_segment;
- gint grab_pointer;
-
- #ifdef PATH_TOOL_DEBUG
- fprintf(stderr, "path_tool_button_press_curve:\n");
- #endif PATH_TOOL_DEBUG
-
- grab_pointer = 1;
-
- if (!cur_path) {
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "Fatal error: No current Path\n");
- #endif PATH_TOOL_DEBUG
- return 0;
- }
-
- draw_core_pause (path_tool->core, tool);
-
- if (path_tool->click_modifier & GDK_SHIFT_MASK) {
- cur_segment = path_curve_insert_anchor (path_tool, path_tool->click_segment, path_tool->click_position);
- path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
- path_set_flags (path_tool, cur_path, path_tool->click_curve, cur_segment, SEGMENT_ACTIVE, 0);
- path_tool->click_type = ON_ANCHOR;
- path_tool->click_segment = cur_segment;
-
- } else {
- path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
- path_set_flags (path_tool, cur_path, path_tool->click_curve, path_tool->click_segment, SEGMENT_ACTIVE, 0);
- path_set_flags (path_tool, cur_path, path_tool->click_curve, path_tool->click_segment->next, SEGMENT_ACTIVE, 0);
- }
- draw_core_resume(path_tool->core, tool);
-
- return 0;
- }
-
- void
- path_tool_button_release (Tool *tool,
- GdkEventButton *bevent,
- gpointer gdisp_ptr)
- {
- GDisplay * gdisp;
- PathTool * path_tool;
-
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "path_tool_button_release\n");
- #endif PATH_TOOL_DEBUG
-
- gdisp = (GDisplay *) gdisp_ptr;
- path_tool = (PathTool *) tool->private;
-
- path_tool->state &= ~PATH_TOOL_DRAG;
-
- gdk_pointer_ungrab (bevent->time);
- gdk_flush ();
- }
-
-
- /**************************************************************
- * The motion-callbacks for the tool
- */
-
- void
- path_tool_motion (Tool *tool,
- GdkEventMotion *mevent,
- gpointer gdisp_ptr)
- {
- GDisplay * gdisp;
- PathTool * path_tool;
-
- if (gtk_events_pending()) return;
-
- gdisp = (GDisplay *) gdisp_ptr;
- path_tool = (PathTool *) tool->private;
-
- switch (path_tool->click_type) {
- case ON_ANCHOR:
- path_tool_motion_anchor (tool, mevent, gdisp);
- break;
- case ON_HANDLE:
- path_tool_motion_handle (tool, mevent, gdisp);
- break;
- case ON_CURVE:
- path_tool_motion_curve (tool, mevent, gdisp);
- break;
- default:
- return;
- }
-
- }
-
- void
- path_tool_motion_anchor (Tool *tool,
- GdkEventMotion *mevent,
- GDisplay *gdisp)
- {
- PathTool * path_tool;
- gdouble dx, dy, d;
- gint x,y;
- static gint dxsum = 0;
- static gint dysum = 0;
-
- path_tool = (PathTool *) tool->private;
-
- /*
- * Dont do anything, if the user clicked with pressed CONTROL-Key,
- * because he deleted an anchor.
- */
- if (path_tool->click_modifier & GDK_CONTROL_MASK)
- return;
-
- if (!(path_tool->state & PATH_TOOL_DRAG))
- {
- path_tool->state |= PATH_TOOL_DRAG;
- dxsum = 0;
- dysum = 0;
- }
-
- gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, TRUE, 0);
-
- dx = x - path_tool->click_x - dxsum;
- dy = y - path_tool->click_y - dysum;
-
- /* restrict to horizontal/vertical lines, if modifiers are pressed
- * I'm not sure, if this is intuitive for the user. Esp. When moving
- * an endpoint of an curve I'd expect, that the *line* is
- * horiz/vertical - not the delta to the point, where the point was
- * originally...
- */
- if (mevent->state & GDK_MOD1_MASK)
- {
- if (mevent->state & GDK_CONTROL_MASK)
- {
- d = (fabs(dx) + fabs(dy)) / 2;
- d = (fabs(x - path_tool->click_x) + fabs(y - path_tool->click_y)) / 2;
-
- dx = ((x < path_tool->click_x) ? -d : d ) - dxsum;
- dy = ((y < path_tool->click_y) ? -d : d ) - dysum;
- }
- else
- dx = - dxsum;
- }
- else if (mevent->state & GDK_CONTROL_MASK)
- dy = - dysum;
-
-
- path_tool->draw |= PATH_TOOL_REDRAW_ACTIVE;
-
- draw_core_pause(path_tool->core, tool);
-
- path_offset_active (path_tool->cur_path, dx, dy);
-
- dxsum += dx;
- dysum += dy;
-
- draw_core_resume (path_tool->core, tool);
-
- path_tool->draw &= ~PATH_TOOL_REDRAW_ACTIVE;
-
- }
-
- void
- path_tool_motion_handle (Tool *tool,
- GdkEventMotion *mevent,
- GDisplay *gdisp)
- {
- PathTool * path_tool;
- gdouble dx, dy;
- gint x,y;
- static gint dxsum = 0;
- static gint dysum = 0;
-
- path_tool = (PathTool *) tool->private;
-
- /*
- * Dont do anything, if the user clicked with pressed CONTROL-Key,
- * because he moved the handle to the anchor an anchor.
- * XXX: Not yet! :-)
- */
- if (path_tool->click_modifier & GDK_CONTROL_MASK)
- return;
-
- if (!(path_tool->state & PATH_TOOL_DRAG))
- {
- path_tool->state |= PATH_TOOL_DRAG;
- dxsum = 0;
- dysum = 0;
- }
-
- gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, TRUE, 0);
-
- dx = x - path_tool->click_x - dxsum;
- dy = y - path_tool->click_y - dysum;
-
- path_tool->draw |= PATH_TOOL_REDRAW_ACTIVE;
-
- draw_core_pause(path_tool->core, tool);
-
- path_curve_drag_handle (path_tool, path_tool->click_segment, dx, dy, path_tool->click_handle_id);
-
- dxsum += dx;
- dysum += dy;
-
- draw_core_resume (path_tool->core, tool);
-
- path_tool->draw &= ~PATH_TOOL_REDRAW_ACTIVE;
-
- }
-
-
- void
- path_tool_motion_curve (Tool *tool,
- GdkEventMotion *mevent,
- GDisplay *gdisp)
- {
- PathTool * path_tool;
- gdouble dx, dy;
- gint x,y;
- static gint dxsum = 0;
- static gint dysum = 0;
-
- path_tool = (PathTool *) tool->private;
-
- if (!(path_tool->state & PATH_TOOL_DRAG))
- {
- path_tool->state |= PATH_TOOL_DRAG;
- dxsum = 0;
- dysum = 0;
- }
-
- gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, TRUE, 0);
-
- dx = x - path_tool->click_x - dxsum;
- dy = y - path_tool->click_y - dysum;
-
- path_tool->draw |= PATH_TOOL_REDRAW_ACTIVE;
-
- draw_core_pause(path_tool->core, tool);
-
- path_curve_drag_segment (path_tool, path_tool->click_segment, path_tool->click_position, dx, dy);
-
- dxsum += dx;
- dysum += dy;
-
- draw_core_resume (path_tool->core, tool);
-
- path_tool->draw &= ~PATH_TOOL_REDRAW_ACTIVE;
-
- }
-
-
- void
- path_tool_cursor_update (Tool *tool,
- GdkEventMotion *mevent,
- gpointer gdisp_ptr)
- {
- PathTool *path_tool;
- GDisplay *gdisp;
- gint x, y, halfwidth, dummy, cursor_location;
-
- #ifdef PATH_TOOL_DEBUG
- /* fprintf (stderr, "path_tool_cursor_update\n");
- */
- #endif PATH_TOOL_DEBUG
-
- gdisp = (GDisplay *) gdisp_ptr;
- path_tool = (PathTool *) tool->private;
-
- gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, TRUE, 0);
- /* get halfwidth in image coord */
- gdisplay_untransform_coords (gdisp, mevent->x + PATH_TOOL_HALFWIDTH, 0, &halfwidth, &dummy, TRUE, 0);
- halfwidth -= x;
-
- cursor_location = path_tool_cursor_position (tool, x, y, halfwidth, NULL, NULL, NULL, NULL, NULL);
-
- switch (cursor_location) {
- case ON_CANVAS:
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE1AP_CURSOR);
- break;
- case ON_ANCHOR:
- gdisplay_install_tool_cursor (gdisp, GDK_FLEUR);
- break;
- case ON_HANDLE:
- gdisplay_install_tool_cursor (gdisp, GDK_CROSSHAIR);
- break;
- case ON_CURVE:
- gdisplay_install_tool_cursor (gdisp, GDK_CROSSHAIR);
- break;
- default:
- gdisplay_install_tool_cursor (gdisp, GDK_QUESTION_ARROW);
- break;
- }
- }
-
- /**************************************************************
- * Tool-control functions
- */
-
- void
- path_tool_control (Tool *tool,
- ToolAction action,
- gpointer gdisp_ptr)
- {
- GDisplay * gdisp;
- PathTool * path_tool;
-
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "path_tool_control\n");
- #endif PATH_TOOL_DEBUG
-
- gdisp = (GDisplay *) tool->gdisp_ptr;
- path_tool = (PathTool *) tool->private;
-
- switch (action)
- {
- case PAUSE:
- draw_core_pause (path_tool->core, tool);
- break;
-
- case RESUME:
- draw_core_resume (path_tool->core, tool);
- break;
-
- case HALT:
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "path_tool_control: HALT\n");
- #endif PATH_TOOL_DEBUG
- draw_core_stop (path_tool->core, tool);
- tool->state = INACTIVE;
- break;
-
- default:
- break;
- }
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "path_tool_control: end\n");
- #endif PATH_TOOL_DEBUG
- }
-
- Tool *
- tools_new_path_tool (void)
- {
- Tool * tool;
- PathTool * private;
-
- /* The tool options */
- if (! path_options)
- {
- path_options = tool_options_new (_("Path Tool"));
- tools_register (PATH_TOOL, (ToolOptions *) path_options);
- }
-
- tool = tools_new_tool (PATH_TOOL);
- private = g_new0 (PathTool, 1);
-
- private->click_type = ON_CANVAS;
- private->click_x = 0;
- private->click_y = 0;
- private->click_halfwidth = 0;
- private->click_modifier = 0;
- private->click_path = NULL;
- private->click_curve = NULL;
- private->click_segment = NULL;
- private->click_position = -1;
-
- private->active_count = 0;
- private->single_active_segment = NULL;
-
- private->state = 0;
- private->draw = PATH_TOOL_REDRAW_ALL;
- private->core = draw_core_new (path_tool_draw);
- private->cur_path = g_new0(Path, 1);
- private->scanlines = NULL;
-
-
- tool->private = (void *) private;
-
- tool->button_press_func = path_tool_button_press;
- tool->button_release_func = path_tool_button_release;
- tool->motion_func = path_tool_motion;
- tool->cursor_update_func = path_tool_cursor_update;
- tool->control_func = path_tool_control;
-
- private->cur_path->curves = NULL;
- private->cur_path->cur_curve = NULL;
- private->cur_path->name = g_string_new("Path 0");
- private->cur_path->state = 0;
- private->cur_path->path_tool = private;
-
- return tool;
- }
-
- void
- tools_free_path_tool (Tool *tool)
- {
- GDisplay * gdisp;
- PathTool * path_tool;
-
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "tools_free_path_tool start\n");
- #endif PATH_TOOL_DEBUG
- path_tool = (PathTool *) tool->private;
- gdisp = (GDisplay *) tool->gdisp_ptr;
-
- if (tool->state == ACTIVE)
- {
- draw_core_stop (path_tool->core, tool);
- }
-
- path_free_path (path_tool->cur_path);
-
- draw_core_free (path_tool->core);
-
- g_free (path_tool);
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "tools_free_path_tool end\n");
- #endif PATH_TOOL_DEBUG
-
- }
-
-
- /**************************************************************
- * Set of function to determine, if the click was on a segment
- */
-
- typedef struct {
- Tool *tool;
- Path *path;
- PathCurve *curve;
- PathSegment *segment;
- gint testx;
- gint testy;
- gint halfwidth;
- gint distance;
- gdouble position;
- gboolean found;
- } Path_on_curve_type;
-
- /* This is a CurveTraverseFunc */
- void
- path_tool_on_curve_helper (Path *path,
- PathCurve *curve,
- PathSegment *segment,
- gpointer ptr)
- {
- gint distance;
- gdouble position;
- Path_on_curve_type *data = (Path_on_curve_type *) ptr;
-
- if (segment && segment->next && data && data->distance > 0)
- {
- position = path_curve_on_segment (data->tool, segment, data->testx, data->testy, data->halfwidth, &distance);
- if (position >= 0 && distance < data->distance )
- {
- data->path = path;
- data->curve = curve;
- data->segment = segment;
- data->distance = distance;
- data->position = position;
- data->found = TRUE;
- }
- }
- }
-
- gdouble
- path_tool_on_curve (Tool *tool,
- gint x,
- gint y,
- gint halfwidth,
- Path **ret_pathP,
- PathCurve **ret_curveP,
- PathSegment **ret_segmentP)
- {
- Path_on_curve_type *data = g_new (Path_on_curve_type, 1);
- gdouble position;
-
- data->tool = tool;
- data->path = NULL;
- data->segment = NULL;
- data->segment = NULL;
- data->testx = x;
- data->testy = y;
- data->halfwidth = halfwidth;
- data->distance = halfwidth * halfwidth + 1;
- data->position = -1;
- data->found = FALSE;
-
- path_traverse_path (((PathTool *) data->tool->private)->cur_path, NULL, path_tool_on_curve_helper, NULL, data);
-
- if (ret_pathP) *ret_pathP = data->path;
- if (ret_curveP) *ret_curveP = data->curve;
- if (ret_segmentP) *ret_segmentP = data->segment;
-
- position = data->position;
-
- g_free(data);
-
- return position;
-
- }
-
- /**************************************************************
- * Set of function to determine, if the click was on an anchor
- */
-
- typedef struct {
- Path *path;
- PathCurve *curve;
- PathSegment *segment;
- gint testx;
- gint testy;
- gint distance;
- gboolean found;
- } Path_on_anchors_type;
-
- /* This is a CurveTraverseFunc */
- void
- path_tool_on_anchors_helper (Path *path,
- PathCurve *curve,
- PathSegment *segment,
- gpointer ptr)
- {
- gint distance;
- Path_on_anchors_type *data = (Path_on_anchors_type *) ptr;
-
- if (segment && data && data->distance > 0)
- {
- distance = ((data->testx - segment->x) * (data->testx - segment->x) +
- (data->testy - segment->y) * (data->testy - segment->y));
-
- if ( distance < data->distance )
- {
- data->path = path;
- data->curve = curve;
- data->segment = segment;
- data->distance = distance;
- data->found = TRUE;
- }
- }
- }
-
- gboolean
- path_tool_on_anchors (Tool *tool,
- gint x,
- gint y,
- gint halfwidth,
- Path **ret_pathP,
- PathCurve **ret_curveP,
- PathSegment **ret_segmentP)
- {
- Path_on_anchors_type *data = g_new (Path_on_anchors_type, 1);
- gboolean ret_found;
-
- data->path = NULL;
- data->curve = NULL;
- data->segment = NULL;
- data->testx = x;
- data->testy = y;
- data->distance = halfwidth * halfwidth + 1;
- data->found = FALSE;
-
- path_traverse_path (((PathTool *) tool->private)->cur_path, NULL, path_tool_on_anchors_helper, NULL, data);
-
- if (ret_pathP) *ret_pathP = data->path;
- if (ret_curveP) *ret_curveP = data->curve;
- if (ret_segmentP) *ret_segmentP = data->segment;
-
- ret_found = data->found;
-
- g_free(data);
-
- return ret_found;
-
- }
-
- /**************************************************************
- * Set of function to determine, if the click was on an handle
- */
-
- typedef struct {
- Path *path;
- PathCurve *curve;
- PathSegment *segment;
- gint testx;
- gint testy;
- gint halfwidth;
- gint handle_id;
- gboolean found;
- } Path_on_handles_type;
-
- /* This is a CurveTraverseFunc */
- void
- path_tool_on_handles_helper (Path *path,
- PathCurve *curve,
- PathSegment *segment,
- gpointer ptr)
- {
- Path_on_handles_type *data = (Path_on_handles_type *) ptr;
- gint handle;
-
- if (segment && data && !data->found)
- {
- handle = path_curve_on_handle (NULL, segment, data->testx, data->testy,
- data->halfwidth);
- if (handle)
- {
- data->path = path;
- data->curve = curve;
- data->segment = segment;
- data->handle_id = handle;
- data->found = TRUE;
- }
- }
- }
-
- gint
- path_tool_on_handles (Tool *tool,
- gint x,
- gint y,
- gint halfwidth,
- Path **ret_pathP,
- PathCurve **ret_curveP,
- PathSegment **ret_segmentP)
- {
- Path_on_handles_type *data = g_new (Path_on_handles_type, 1);
- gint handle_ret;
-
- data->path = NULL;
- data->curve = NULL;
- data->segment = NULL;
- data->testx = x;
- data->testy = y;
- data->halfwidth = halfwidth;
- data->handle_id = 0;
- data->found = FALSE;
-
- path_traverse_path (((PathTool *) tool->private)->cur_path, NULL, path_tool_on_handles_helper, NULL, data);
-
- if (ret_pathP) *ret_pathP = data->path;
- if (ret_curveP) *ret_curveP = data->curve;
- if (ret_segmentP) *ret_segmentP = data->segment;
-
- handle_ret = data->handle_id;
-
- g_free(data);
-
- return handle_ret;
- }
-
-
- /**************************************************************
- * Set of function to offset all active anchors
- */
-
- typedef struct {
- gdouble dx;
- gdouble dy;
- } Path_offset_active_type;
-
- /* This is a CurveTraverseFunc */
- void
- path_offset_active_helper (Path *path,
- PathCurve *curve,
- PathSegment *segment,
- gpointer ptr)
- {
- Path_offset_active_type *data = (Path_offset_active_type *) ptr;
-
- if (segment && data && (segment->flags & SEGMENT_ACTIVE)) {
- segment->x += data->dx;
- segment->y += data->dy;
- }
- /* XXX: Do a segment_update here! */
- }
-
- void
- path_offset_active (Path *path,
- gdouble dx,
- gdouble dy)
- {
- Path_offset_active_type *data = g_new (Path_offset_active_type, 1);
- data->dx = dx;
- data->dy = dy;
-
- if (path)
- path_traverse_path (path, NULL, path_offset_active_helper, NULL, data);
-
- g_free(data);
- }
-
-
- /**************************************************************
- * Set of function to set the state of all anchors
- */
-
- typedef struct {
- guint32 bits_set;
- guint32 bits_clear;
- PathTool *path_tool;
- } Path_set_flags_type;
-
- /* This is a CurveTraverseFunc */
- void
- path_set_flags_helper (Path *path,
- PathCurve *curve,
- PathSegment *segment,
- gpointer ptr)
- {
- Path_set_flags_type *tmp = (Path_set_flags_type *) ptr;
- guint32 oldflags;
- guint tmp_uint;
-
- if (segment) {
- oldflags = segment->flags;
- segment->flags &= ~(tmp->bits_clear);
- segment->flags |= tmp->bits_set;
-
- /*
- * Some black magic: We try to remember, which is the single active segment.
- * We count, how many segments are active (in path_tool->active_count) and
- * XOR path_tool->single_active_segment every time we select or deselect
- * an anchor. So if exactly one anchor is active, path_tool->single_active_segment
- * points to it.
- */
-
- /* If SEGMENT_ACTIVE state has changed change the PathTool data accordingly.*/
- if (((segment->flags ^ oldflags) & SEGMENT_ACTIVE) && tmp && tmp->path_tool) {
- if (segment->flags & SEGMENT_ACTIVE)
- tmp->path_tool->active_count++;
- else
- tmp->path_tool->active_count--;
-
- /* Does this work on all (16|32|64)-bit Machines? */
-
- tmp_uint = GPOINTER_TO_UINT(tmp->path_tool->single_active_segment);
- tmp_uint ^= GPOINTER_TO_UINT(segment);
- tmp->path_tool->single_active_segment = GUINT_TO_POINTER(tmp_uint);
- }
- }
- }
-
- void
- path_set_flags (PathTool *path_tool,
- Path *path,
- PathCurve *curve,
- PathSegment *segment,
- guint32 bits_set,
- guint32 bits_clear)
- {
- Path_set_flags_type *tmp = g_new (Path_set_flags_type, 1);
- tmp->bits_set=bits_set;
- tmp->bits_clear=bits_clear;
- tmp->path_tool = path_tool;
-
- if (segment)
- path_set_flags_helper (path, curve, segment, tmp);
- else if (curve)
- path_traverse_curve (path, curve, path_set_flags_helper, NULL, tmp);
- else if (path)
- path_traverse_path (path, NULL, path_set_flags_helper, NULL, tmp);
-
- g_free (tmp);
- }
-
-
- /**************************************************************
- * Set of functions to draw the segments to the window
- */
-
- /* This is a CurveTraverseFunc */
- void
- path_tool_draw_helper (Path *path,
- PathCurve *curve,
- PathSegment *segment,
- gpointer tool_ptr)
- {
- Tool * tool = (Tool *) tool_ptr;
- GDisplay * gdisp;
- PathTool * path_tool;
- DrawCore * core;
- gint x1, y1;
- gboolean draw = TRUE;
-
- if (!tool) {
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "Fatal Error: path_tool_draw_segment called without valid tool *\n");
- #endif PATH_TOOL_DEBUG
- return;
- }
-
- gdisp = tool->gdisp_ptr;
-
- path_tool = (PathTool *) tool->private;
- core = path_tool->core;
-
- if (path_tool->draw & PATH_TOOL_REDRAW_ACTIVE)
- draw = (segment->flags & SEGMENT_ACTIVE || (segment->next && segment->next->flags & SEGMENT_ACTIVE));
-
- if (segment && draw)
- {
- gdisplay_transform_coords (gdisp, (gint) segment->x, (gint) segment->y, &x1, &y1, FALSE);
- if (segment->flags & SEGMENT_ACTIVE)
- gdk_draw_arc (core->win, core->gc, 0,
- x1 - PATH_TOOL_HALFWIDTH, y1 - PATH_TOOL_HALFWIDTH,
- PATH_TOOL_WIDTH, PATH_TOOL_WIDTH, 0, 23040);
- else
- gdk_draw_arc (core->win, core->gc, 1,
- x1 - PATH_TOOL_HALFWIDTH, y1 - PATH_TOOL_HALFWIDTH,
- PATH_TOOL_WIDTH, PATH_TOOL_WIDTH, 0, 23040);
-
- path_curve_draw_handles (tool, segment);
-
- if (segment->next)
- {
- path_curve_draw_segment (tool, segment);
- }
- }
- #ifdef PATH_TOOL_DEBUG
- else if (!segment)
- fprintf(stderr, "path_tool_draw_segment: no segment to draw\n");
- #endif PATH_TOOL_DEBUG
- }
-
- void
- path_tool_draw (Tool *tool)
- {
- GDisplay * gdisp;
- Path * cur_path;
- PathTool * path_tool;
-
- #ifdef PATH_TOOL_DEBUG
- fprintf (stderr, "path_tool_draw\n");
- #endif PATH_TOOL_DEBUG
-
- gdisp = tool->gdisp_ptr;
- path_tool = tool->private;
- cur_path = path_tool->cur_path;
-
- path_traverse_path (cur_path, NULL, path_tool_draw_helper, NULL, tool);
-
- #ifdef PATH_TOOL_DEBUG
- /* fprintf (stderr, "path_tool_draw end.\n");
- */
- #endif PATH_TOOL_DEBUG
-
- }
-
-
-