Files
gimp/app/tools/path_tool.c
Simon Budig e2f373cbd2 app/Makefile.am app/apptypes.h app/path_bezier.[ch] app/path_curves.[ch]
2001-04-07  Simon Budig  <simon@gimp.org>

        * app/Makefile.am
        * app/apptypes.h
        * app/path_bezier.[ch]
        * app/path_curves.[ch]
        * app/pixmaps2.h
        * app/tools/Makefile.am
        * app/tools/gimpdrawtool.[ch]
        * app/tools/path_tool.[ch]
        * app/tools/path_toolP.h
        * app/tools/tools.c

        new files:
        * app/tools/gimppathtool.c
        * app/tools/gimppathtool.h

        Reactivated (at least partially) the old new path tool. It
        will undergo major restructuring. Especially the path data
        will become proper objects. This definitely is work in progress
        and totally unuseable now.
2001-04-07 14:55:39 +00:00

1921 lines
48 KiB
C

/* 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 "path_curves.h"
#include "config.h"
#include "libgimp/gimpintl.h"
*/
#include <glib.h>
#include <gdk/gdk.h>
#include "apptypes.h"
#include "path_curves.h"
#include "path_tool.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 (NPath *,
PathTraverseFunc,
CurveTraverseFunc,
SegmentTraverseFunc,
gpointer);
void path_traverse_curve (NPath *,
PathCurve *,
CurveTraverseFunc,
SegmentTraverseFunc,
gpointer);
void path_traverse_segment (NPath *,
PathCurve *,
PathSegment *,
SegmentTraverseFunc,
gpointer);
gdouble path_locate_point (NPath *,
PathCurve **,
PathSegment **,
gint,
gint,
gint,
gint,
gint);
gdouble path_tool_on_curve (NPath *path,
gint x,
gint y,
gint halfwidth,
NPath **ret_pathP,
PathCurve **ret_curveP,
PathSegment **ret_segmentP);
/* Tools to manipulate paths, curves, segments */
PathCurve * path_add_curve (NPath *,
gint,
gint);
PathSegment * path_append_segment (NPath *,
PathCurve *,
SegmentType,
gint,
gint);
PathSegment * path_prepend_segment (NPath *,
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 (NPath *);
void path_free_curve (PathCurve *);
void path_free_segment (PathSegment *);
void path_delete_segment (PathSegment *);
void path_print (NPath *);
void path_offset_active (NPath *, gdouble, gdouble);
void path_set_flags (GimpPathTool *,
NPath *,
PathCurve *,
PathSegment *,
guint32,
guint32);
/* High level image-manipulation functions */
void path_stroke (GimpPathTool *,
NPath *);
void path_to_selection (GimpPathTool *,
NPath *);
/* Functions necessary for the tool */
#if 0
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,
NPath**, PathCurve**, PathSegment**);
gboolean path_tool_on_anchors (Tool *, gint, gint, gint,
NPath**, PathCurve**, PathSegment**);
gint path_tool_on_handles (Tool *, gint, gint, gint,
NPath **, 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 *);
#endif
/* 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 (NPath *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 (NPath *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 (NPath *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 (NPath * 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 (NPath * 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 (NPath * 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;
path_curve_get_point (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 (NPath * 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 (NULL, 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 (NPath *path,
gint x,
gint y,
gint halfwidth,
NPath **pathP,
PathCurve **curveP,
PathSegment **segmentP,
gdouble *positionP,
gint *handle_idP)
{
gdouble pos;
gint handle_id;
if (path_tool_on_anchors (path, x, y, halfwidth, pathP, curveP, segmentP))
return ON_ANCHOR;
handle_id = path_tool_on_handles (path, x, y, halfwidth, pathP, curveP, segmentP);
if (handle_id) {
if (handle_idP) (*handle_idP) = handle_id;
return ON_HANDLE;
}
pos = path_tool_on_curve (path, x, y, halfwidth, pathP, curveP, segmentP);
if (pos >= 0 && pos <= 1) {
if (positionP) (*positionP) = pos;
return ON_CURVE;
}
return ON_CANVAS;
}
#if 0
/**************************************************************
* The click-callbacks for the tool
*/
void
path_tool_button_press (Tool *tool,
GdkEventButton *bevent,
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
path_tool = (PathTool *) tool->private;
tool->gdisp = gdisp;
/* 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;
NPath * 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;
NPath * 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;
NPath * 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;
NPath * 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 NPath\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,
GDisplay *gdisp)
{
PathTool * path_tool;
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "path_tool_button_release\n");
#endif PATH_TOOL_DEBUG
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,
GDisplay *gdisp)
{
PathTool * path_tool;
if (gtk_events_pending()) return;
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,
GDisplay *gdisp)
{
PathTool *path_tool;
gint x, y, halfwidth, dummy, cursor_location;
#ifdef PATH_TOOL_DEBUG
/* fprintf (stderr, "path_tool_cursor_update\n");
*/
#endif PATH_TOOL_DEBUG
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,
GDisplay *gdisp)
{
PathTool * path_tool;
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "path_tool_control\n");
#endif PATH_TOOL_DEBUG
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(NPath, 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 = tool->gdisp;
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
}
#endif
/**************************************************************
* Set of function to determine, if the click was on a segment
*/
typedef struct {
NPath *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 (NPath *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 (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 (NPath *path,
gint x,
gint y,
gint halfwidth,
NPath **ret_pathP,
PathCurve **ret_curveP,
PathSegment **ret_segmentP)
{
Path_on_curve_type *data = g_new (Path_on_curve_type, 1);
gdouble position;
data->path = path;
data->curve = 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 (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 {
NPath *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 (NPath *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 (NPath *path,
gint x,
gint y,
gint halfwidth,
NPath **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 = path;
data->curve = NULL;
data->segment = NULL;
data->testx = x;
data->testy = y;
data->distance = halfwidth * halfwidth + 1;
data->found = FALSE;
path_traverse_path (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 {
NPath *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 (NPath *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 (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 (NPath *path,
gint x,
gint y,
gint halfwidth,
NPath **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 = path;
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 (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 (NPath *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 (NPath *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;
GimpPathTool *path_tool;
} Path_set_flags_type;
/* This is a CurveTraverseFunc */
void
path_set_flags_helper (NPath *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 0
/* 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);
}
#endif
}
}
void
path_set_flags (GimpPathTool *path_tool,
NPath *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 (NPath *path,
PathCurve *curve,
PathSegment *segment,
gpointer tool_ptr)
{
#if 0
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;
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
#endif
}
void
path_tool_draw (Tool *tool)
{
#if 0
GDisplay * gdisp;
NPath * cur_path;
PathTool * path_tool;
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "path_tool_draw\n");
#endif PATH_TOOL_DEBUG
gdisp = tool->gdisp;
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
#endif
}