applied a patch from Simon.

--Sven
This commit is contained in:
Sven Neumann 1999-09-15 10:54:25 +00:00
parent e422b59e59
commit e56ff58b04
8 changed files with 1142 additions and 158 deletions

View File

@ -1,3 +1,16 @@
Wed Sep 15 12:43:39 MEST 1999 Simon Budig <Simon.Budig@unix-ag.org>
* app/tools.c
* app/pixmaps2.h
* app/path_tool.c
* app/path_toolP.h
Own pixmap for the Path Tool. It is now possible to connect
open ends of curves. Simply activate one end and shift click
on the other. Control-Click deletes points.
Still no bezier/painting functions...
1999-09-14 Tor Lillqvist <tml@iki.fi> 1999-09-14 Tor Lillqvist <tml@iki.fi>
* app/brush_select.c: Include config.h, guard inclusion of * app/brush_select.c: Include config.h, guard inclusion of

View File

@ -29,6 +29,8 @@
* segments between two anchors. * segments between two anchors.
*/ */
#undef PATH_TOOL_DEBUG
#include <math.h> #include <math.h>
/* #include "appenv.h" /* #include "appenv.h"
*/ */
@ -38,7 +40,9 @@
#include "path_tool.h" #include "path_tool.h"
#include "path_toolP.h" #include "path_toolP.h"
#ifdef PATH_TOOL_DEBUG
#include <stdio.h> #include <stdio.h>
#endif PATH_TOOL_DEBUG
#include "libgimp/gimpintl.h" #include "libgimp/gimpintl.h"
@ -68,15 +72,18 @@ static gdouble path_locate_point (Path *, PathCurve **, PathSegment *
/* Tools to manipulate paths, curves, segments */ /* Tools to manipulate paths, curves, segments */
static PathCurve * path_add_curve (Path *, gint, gint); static PathCurve * path_add_curve (Path *, gint, gint);
static inline PathSegment * path_append_segment (Path *, PathCurve *, SegmentType, gint, gint); static PathSegment * path_append_segment (Path *, PathCurve *, SegmentType, gint, gint);
static PathSegment * path_prepend_segment (Path *, PathCurve *, SegmentType, gint, gint); static PathSegment * path_prepend_segment (Path *, PathCurve *, SegmentType, gint, gint);
static PathSegment * path_split_segment (PathSegment *, gdouble); static PathSegment * path_split_segment (PathSegment *, gdouble);
static void path_join_curves (PathSegment *, PathSegment *);
static void path_flip_curve (PathCurve *);
static void path_free_path (Path *); static void path_free_path (Path *);
static void path_free_curve (PathCurve *); static void path_free_curve (PathCurve *);
static void path_free_segment (PathSegment *); static void path_free_segment (PathSegment *);
static void path_delete_segment (PathSegment *);
static void path_print (Path *); static void path_print (Path *);
static void path_offset_active (Path *, gdouble, gdouble); static void path_offset_active (Path *, gdouble, gdouble);
static void path_clear_active (Path *, PathCurve *, PathSegment *); static void path_set_flags (PathTool *, Path *, PathCurve *, PathSegment *, guint32, guint32);
/* High level image-manipulation functions */ /* High level image-manipulation functions */
@ -116,8 +123,9 @@ static ToolOptions *path_options = NULL;
*/ */
/* /*
* These functions are for applying a function over a complete path/curve/segment * These functions are for applying a function over a complete
* they can pass information to each other with a arbitrary data structure * path/curve/segment. They can pass information to each other
* with a arbitrary data structure
* *
* The idea behind the three different functions is: * The idea behind the three different functions is:
* if pathfunc != NULL * if pathfunc != NULL
@ -176,7 +184,9 @@ path_traverse_curve (Path *path, PathCurve *curve, CurveTraverseFunc curvefunc,
static void static void
path_traverse_segment (Path *path, PathCurve *curve, PathSegment *segment, SegmentTraverseFunc function, gpointer data) path_traverse_segment (Path *path, PathCurve *curve, PathSegment *segment, SegmentTraverseFunc function, gpointer data)
{ {
#ifdef PATH_TOOL_DEBUG
fprintf(stderr, "path_traverse_segment\n"); fprintf(stderr, "path_traverse_segment\n");
#endif PATH_TOOL_DEBUG
/* Something like: /* Something like:
* for i = 1 to subsamples { * for i = 1 to subsamples {
@ -190,34 +200,48 @@ path_traverse_segment (Path *path, PathCurve *curve, PathSegment *segment, Segme
* Helper functions for manipulating the data-structures: * Helper functions for manipulating the data-structures:
*/ */
static PathCurve * path_add_curve (Path * cur_path, gint x, gint y) static PathCurve *path_add_curve (Path * cur_path, gint x, gint y)
{ {
PathCurve * tmp = cur_path->curves; PathCurve * tmp = cur_path->curves;
PathCurve * new_curve; PathCurve * new_curve = NULL;
#ifdef PATH_TOOL_DEBUG
fprintf(stderr, "path_add_curve\n"); fprintf(stderr, "path_add_curve\n");
#endif PATH_TOOL_DEBUG
new_curve = g_new (PathCurve, 1); if (cur_path) {
new_curve = g_new (PathCurve, 1);
new_curve->next = tmp; new_curve->parent = cur_path;
new_curve->prev = NULL; new_curve->next = tmp;
new_curve->cur_segment = NULL; new_curve->prev = NULL;
new_curve->segments = NULL; new_curve->cur_segment = NULL;
new_curve->segments = NULL;
if (tmp) tmp->prev = new_curve; if (tmp) tmp->prev = new_curve;
cur_path->curves = cur_path->cur_curve = new_curve; cur_path->curves = cur_path->cur_curve = new_curve;
new_curve->segments = path_append_segment (cur_path, new_curve, SEGMENT_LINE, x, y); new_curve->segments = path_prepend_segment (cur_path, new_curve, SEGMENT_LINE, 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; return new_curve;
} }
static inline PathSegment * path_append_segment (Path * cur_path, PathCurve * cur_curve, SegmentType type, gint x, gint y) static PathSegment * path_append_segment (Path * cur_path, PathCurve * cur_curve, SegmentType type, gint x, gint y)
{ {
PathSegment * tmp = cur_curve->segments; PathSegment * tmp = cur_curve->segments;
PathSegment * new_segment = NULL; PathSegment * new_segment = NULL;
#ifdef PATH_TOOL_DEBUG
fprintf(stderr, "path_append_segment\n");
#endif PATH_TOOL_DEBUG
if (cur_curve) { if (cur_curve) {
tmp = cur_curve->segments; tmp = cur_curve->segments;
while (tmp && tmp->next && tmp->next != cur_curve->segments) { while (tmp && tmp->next && tmp->next != cur_curve->segments) {
@ -230,32 +254,239 @@ static inline PathSegment * path_append_segment (Path * cur_path, PathCurve * c
new_segment->type = type; new_segment->type = type;
new_segment->x = x; new_segment->x = x;
new_segment->y = y; new_segment->y = y;
new_segment->flags = SEGMENT_ACTIVE; new_segment->flags = 0;
new_segment->parent = cur_curve;
new_segment->next = NULL; new_segment->next = NULL;
new_segment->prev = tmp; new_segment->prev = tmp;
new_segment->data = NULL; new_segment->data = NULL;
if (tmp) if (tmp)
{
tmp->next = new_segment; tmp->next = new_segment;
}
cur_curve->cur_segment = new_segment; cur_curve->cur_segment = new_segment;
} }
#ifdef PATH_TOOL_DEBUG
else else
fprintf(stderr, "Fatal Error: path_append_segment called with a closed curve\n"); fprintf(stderr, "Fatal Error: path_append_segment called with a closed curve\n");
#endif PATH_TOOL_DEBUG
} }
#ifdef PATH_TOOL_DEBUG
else else
fprintf(stderr, "Fatal Error: path_append_segment called without valid curve\n"); fprintf(stderr, "Fatal Error: path_append_segment called without valid curve\n");
#endif PATH_TOOL_DEBUG
return new_segment; return new_segment;
} }
/* static PathSegment * path_prepend_segment (Path *, PathCurve *, gint, gint); static PathSegment * path_prepend_segment (Path * cur_path, PathCurve * cur_curve, SegmentType type, gint x, gint y)
* static PathSegment * path_split_segment (PathSegment *, gdouble); {
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;
}
#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;
}
/* static PathSegment * path_split_segment (PathSegment *, gdouble);
*/ */
/*
* Join two arbitrary endpoints and free the parent from the second
* segment, if it differs from the first parents.
*/
static 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;
}
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;
}
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;
}
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "Cant join these curves yet...\n");
return;
#endif PATH_TOOL_DEBUG
}
/*
* This function reverses the order of the anchors. This is
* necessary for some joining operations.
*/
static 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;
}
tmp = tmp->next;
}
}
static void static void
path_free_path (Path * path) path_free_path (Path * path)
{ {
@ -283,13 +514,17 @@ path_free_curve (PathCurve *curve)
if (curve) if (curve)
{ {
tmp2 = curve->segments; tmp2 = curve->segments;
g_free(curve);
/* break closed curves */
if (tmp2 && tmp2->prev)
tmp2->prev->next = NULL;
while ((tmp1 = tmp2) != NULL) while ((tmp1 = tmp2) != NULL)
{ {
tmp2 = tmp1->next; tmp2 = tmp1->next;
path_free_segment (tmp1); path_free_segment (tmp1);
} }
g_free(curve);
} }
} }
@ -298,12 +533,62 @@ path_free_segment (PathSegment *segment)
{ {
if (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);
if (segment->data) if (segment->data)
g_free(segment->data); g_free(segment->data);
g_free (segment); g_free (segment);
} }
} }
static 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);
}
}
static 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
*/
}
}
/* /*
@ -336,7 +621,9 @@ path_tool_button_press (Tool *tool,
gint grab_pointer=0; gint grab_pointer=0;
gint x, y, halfwidth, dummy; gint x, y, halfwidth, dummy;
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "path_tool_button_press\n"); fprintf (stderr, "path_tool_button_press\n");
#endif PATH_TOOL_DEBUG
gdisp = (GDisplay *) gdisp_ptr; gdisp = (GDisplay *) gdisp_ptr;
path_tool = (PathTool *) tool->private; path_tool = (PathTool *) tool->private;
@ -344,7 +631,9 @@ path_tool_button_press (Tool *tool,
/* Transform window-coordinates to canvas-coordinates */ /* Transform window-coordinates to canvas-coordinates */
gdisplay_untransform_coords (gdisp, bevent->x, bevent->y, &x, &y, TRUE, 0); gdisplay_untransform_coords (gdisp, bevent->x, bevent->y, &x, &y, TRUE, 0);
#ifdef PATH_TOOL_DEBUG
fprintf(stderr, "Clickcoordinates %d, %d\n",x,y); fprintf(stderr, "Clickcoordinates %d, %d\n",x,y);
#endif PATH_TOOL_DEBUG
path_tool->click_x = x; path_tool->click_x = x;
path_tool->click_y = y; path_tool->click_y = y;
path_tool->click_modifier = bevent->state; path_tool->click_modifier = bevent->state;
@ -395,20 +684,42 @@ path_tool_button_press_anchor (Tool *tool,
GdkEventButton *bevent, GdkEventButton *bevent,
GDisplay *gdisp) GDisplay *gdisp)
{ {
static guint32 last_click_time=0;
gboolean doubleclick=FALSE;
PathTool *path_tool = tool->private; PathTool *path_tool = tool->private;
Path * cur_path = path_tool->cur_path; Path * cur_path = path_tool->cur_path;
PathSegment *p_sas;
gint grab_pointer; gint grab_pointer;
#ifdef PATH_TOOL_DEBUG
fprintf(stderr, "path_tool_button_press_anchor:\n"); fprintf(stderr, "path_tool_button_press_anchor:\n");
#endif PATH_TOOL_DEBUG
grab_pointer = 1; grab_pointer = 1;
if (!cur_path) { if (!cur_path) {
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "Fatal error: No current Path\n"); fprintf (stderr, "Fatal error: No current Path\n");
#endif PATH_TOOL_DEBUG
return 0; 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); draw_core_pause (path_tool->core, tool);
/* The user pressed on an anchor: /* The user pressed on an anchor:
@ -416,15 +727,75 @@ path_tool_button_press_anchor (Tool *tool,
* + SHIFT toggles the activity of an anchor. * + SHIFT toggles the activity of an anchor.
* if this anchor is at the end of an open curve and the other * if this anchor is at the end of an open curve and the other
* end is active, close the curve. * end is active, close the curve.
*
* Doubleclick (de)activates the whole curve (not Path!).
*/ */
if (path_tool->click_modifier & GDK_SHIFT_MASK) p_sas = path_tool->single_active_segment;
path_tool->click_segment->flags ^= SEGMENT_ACTIVE;
else { #ifdef PATH_TOOL_DEBUG
if (!(path_tool->click_segment->flags & SEGMENT_ACTIVE)) fprintf (stderr, "p_sas: %p\n", p_sas);
path_clear_active (cur_path, NULL, NULL); #endif PATH_TOOL_DEBUG
path_tool->click_segment->flags |= SEGMENT_ACTIVE;
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;
}
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);
}
/* Action goes here */ /* Action goes here */
@ -445,35 +816,47 @@ path_tool_button_press_canvas (Tool *tool,
PathSegment * cur_segment; PathSegment * cur_segment;
gint grab_pointer; gint grab_pointer;
#ifdef PATH_TOOL_DEBUG
fprintf(stderr, "path_tool_button_press_canvas:\n"); fprintf(stderr, "path_tool_button_press_canvas:\n");
#endif PATH_TOOL_DEBUG
grab_pointer = 1; grab_pointer = 1;
if (!cur_path) { if (!cur_path) {
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "Fatal error: No current Path\n"); fprintf (stderr, "Fatal error: No current Path\n");
#endif PATH_TOOL_DEBUG
return 0; return 0;
} }
draw_core_pause (path_tool->core, tool); draw_core_pause (path_tool->core, tool);
path_clear_active (cur_path, NULL, NULL); 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;
if (!(cur_curve = cur_path->cur_curve)) { 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_LINE, path_tool->click_x, path_tool->click_y);
else
cur_curve->cur_segment = path_prepend_segment(cur_path, cur_curve, SEGMENT_LINE, 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 {
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); cur_path->cur_curve = path_add_curve(cur_path, path_tool->click_x, path_tool->click_y);
draw_core_resume(path_tool->core, tool); path_set_flags (path_tool, cur_path, cur_path->cur_curve, cur_path->cur_curve->segments, SEGMENT_ACTIVE, 0);
return 0;
} }
cur_curve->cur_segment = path_append_segment(cur_path, cur_curve, SEGMENT_LINE, path_tool->click_x, path_tool->click_y);
draw_core_resume(path_tool->core, tool); draw_core_resume(path_tool->core, tool);
return 0; return 0;
} }
static void static void
path_tool_button_release (Tool *tool, path_tool_button_release (Tool *tool,
GdkEventButton *bevent, GdkEventButton *bevent,
@ -482,13 +865,14 @@ path_tool_button_release (Tool *tool,
GDisplay * gdisp; GDisplay * gdisp;
PathTool * path_tool; PathTool * path_tool;
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "path_tool_button_release\n"); fprintf (stderr, "path_tool_button_release\n");
#endif PATH_TOOL_DEBUG
gdisp = (GDisplay *) gdisp_ptr; gdisp = (GDisplay *) gdisp_ptr;
path_tool = (PathTool *) tool->private; path_tool = (PathTool *) tool->private;
path_tool->state &= ~PATH_TOOL_DRAG; path_tool->state &= ~PATH_TOOL_DRAG;
path_tool->state = 0;
gdk_pointer_ungrab (bevent->time); gdk_pointer_ungrab (bevent->time);
gdk_flush (); gdk_flush ();
@ -507,6 +891,8 @@ path_tool_motion (Tool *tool,
GDisplay * gdisp; GDisplay * gdisp;
PathTool * path_tool; PathTool * path_tool;
if (gtk_events_pending()) return;
gdisp = (GDisplay *) gdisp_ptr; gdisp = (GDisplay *) gdisp_ptr;
path_tool = (PathTool *) tool->private; path_tool = (PathTool *) tool->private;
@ -526,39 +912,68 @@ path_tool_motion_anchor (Tool *tool,
GDisplay *gdisp) GDisplay *gdisp)
{ {
PathTool * path_tool; PathTool * path_tool;
gdouble dx, dy; gdouble dx, dy, d;
gint x,y; gint x,y;
static gint lastx = 0; static gint dxsum = 0;
static gint lasty = 0; static gint dysum = 0;
if (gtk_events_pending()) return; /* Is this OK? I want to ignore just the motion-events... */
path_tool = (PathTool *) tool->private; 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)) if (!(path_tool->state & PATH_TOOL_DRAG))
{ {
path_tool->state |= PATH_TOOL_DRAG; path_tool->state |= PATH_TOOL_DRAG;
lastx = path_tool->click_x; dxsum = 0;
lasty = path_tool->click_y; dysum = 0;
} }
gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, TRUE, 0); gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, TRUE, 0);
dx = x - lastx; dx = x - path_tool->click_x - dxsum;
dy = y - lasty; 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; path_tool->draw |= PATH_TOOL_REDRAW_ACTIVE;
draw_core_pause(path_tool->core, tool); draw_core_pause(path_tool->core, tool);
path_offset_active (path_tool->cur_path, dx, dy); path_offset_active (path_tool->cur_path, dx, dy);
dxsum += dx;
dysum += dy;
draw_core_resume (path_tool->core, tool); draw_core_resume (path_tool->core, tool);
path_tool->draw &= ~PATH_TOOL_REDRAW_ACTIVE; path_tool->draw &= ~PATH_TOOL_REDRAW_ACTIVE;
lastx = x;
lasty = y;
} }
@ -571,8 +986,10 @@ path_tool_cursor_update (Tool *tool,
GDisplay *gdisp; GDisplay *gdisp;
gint x, y, halfwidth, dummy, cursor_location; gint x, y, halfwidth, dummy, cursor_location;
#ifdef PATH_TOOL_DEBUG
/* fprintf (stderr, "path_tool_cursor_update\n"); /* fprintf (stderr, "path_tool_cursor_update\n");
*/ */
#endif PATH_TOOL_DEBUG
gdisp = (GDisplay *) gdisp_ptr; gdisp = (GDisplay *) gdisp_ptr;
path_tool = (PathTool *) tool->private; path_tool = (PathTool *) tool->private;
@ -609,7 +1026,9 @@ path_tool_control (Tool *tool,
GDisplay * gdisp; GDisplay * gdisp;
PathTool * path_tool; PathTool * path_tool;
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "path_tool_control\n"); fprintf (stderr, "path_tool_control\n");
#endif PATH_TOOL_DEBUG
gdisp = (GDisplay *) tool->gdisp_ptr; gdisp = (GDisplay *) tool->gdisp_ptr;
path_tool = (PathTool *) tool->private; path_tool = (PathTool *) tool->private;
@ -655,6 +1074,10 @@ tools_new_path_tool (void)
private->click_y = 0; private->click_y = 0;
private->click_halfwidth = 0; private->click_halfwidth = 0;
private->click_modifier = 0; private->click_modifier = 0;
private->active_count = 0;
private->single_active_segment = NULL;
private->state = 0; private->state = 0;
private->draw = PATH_TOOL_REDRAW_ALL; private->draw = PATH_TOOL_REDRAW_ALL;
private->core = draw_core_new (path_tool_draw); private->core = draw_core_new (path_tool_draw);
@ -674,6 +1097,7 @@ tools_new_path_tool (void)
private->cur_path->cur_curve = NULL; private->cur_path->cur_curve = NULL;
private->cur_path->name = g_string_new("Path 0"); private->cur_path->name = g_string_new("Path 0");
private->cur_path->state = 0; private->cur_path->state = 0;
private->cur_path->path_tool = private;
return tool; return tool;
} }
@ -701,7 +1125,7 @@ tools_free_path_tool (Tool *tool)
/************************************************************** /**************************************************************
* Set of tools to determine, if the click was on an anchor * Set of function to determine, if the click was on an anchor
*/ */
typedef struct { typedef struct {
@ -767,7 +1191,7 @@ path_tool_on_anchors (Tool *tool, gint x, gint y, gint halfwidth, Path **ret_pat
/************************************************************** /**************************************************************
* Set of tools to offset all active anchors * Set of function to offset all active anchors
*/ */
typedef struct { typedef struct {
@ -802,34 +1226,70 @@ path_offset_active (Path *path, gdouble dx, gdouble dy)
/************************************************************** /**************************************************************
* Set of tools to set the state of all anchors to inactive * Set of function to set the state of all anchors to inactive
*/ */
typedef struct {
guint32 bits_set;
guint32 bits_clear;
PathTool *path_tool;
} Path_set_flags_type;
/* This is a CurveTraverseFunc */ /* This is a CurveTraverseFunc */
static void static void
path_clear_active_helper (Path *path, PathCurve *curve, PathSegment *segment, gpointer ptr) path_set_flags_helper (Path *path, PathCurve *curve, PathSegment *segment, gpointer ptr)
{ {
gint distance; Path_set_flags_type *tmp = (Path_set_flags_type *) ptr;
guint32 oldflags;
if (segment) {
oldflags = segment->flags;
segment->flags &= ~(tmp->bits_clear);
segment->flags |= tmp->bits_set;
if (segment) /*
segment->flags &= ~SEGMENT_ACTIVE; * 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? */
GPOINTER_TO_UINT(tmp->path_tool->single_active_segment) ^= GPOINTER_TO_UINT(segment);
}
}
} }
static void static void
path_clear_active (Path *path, PathCurve *curve, PathSegment *segment) path_set_flags (PathTool *path_tool, Path *path, PathCurve *curve, PathSegment *segment, guint32 bits_set, guint32 bits_clear)
{ {
fprintf (stderr, "path_clear_active\n"); 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) if (segment)
path_clear_active_helper (path, curve, segment, NULL); path_set_flags_helper (path, curve, segment, tmp);
else if (curve) else if (curve)
path_traverse_curve (path, curve, path_clear_active_helper, NULL, NULL); path_traverse_curve (path, curve, path_set_flags_helper, NULL, tmp);
else if (path) else if (path)
path_traverse_path (path, NULL, path_clear_active_helper, NULL, NULL); path_traverse_path (path, NULL, path_set_flags_helper, NULL, tmp);
g_free (tmp);
} }
/************************************************************** /**************************************************************
* Set of tools to draw the segments to the window * Set of functions to draw the segments to the window
*/ */
/* This is a CurveTraverseFunc */ /* This is a CurveTraverseFunc */
@ -840,10 +1300,13 @@ path_tool_draw_helper (Path *path, PathCurve *curve, PathSegment * segment, gpoi
GDisplay * gdisp; GDisplay * gdisp;
PathTool * path_tool; PathTool * path_tool;
DrawCore * core; DrawCore * core;
gint x1, y1, x2, y2, draw; gint x1, y1, x2, y2;
gboolean draw = TRUE;
if (!tool) { if (!tool) {
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "Fatal Error: path_tool_draw_segment called without valid tool *\n"); fprintf (stderr, "Fatal Error: path_tool_draw_segment called without valid tool *\n");
#endif PATH_TOOL_DEBUG
return; return;
} }
@ -852,15 +1315,8 @@ path_tool_draw_helper (Path *path, PathCurve *curve, PathSegment * segment, gpoi
path_tool = (PathTool *) tool->private; path_tool = (PathTool *) tool->private;
core = path_tool->core; core = path_tool->core;
draw = 1;
if (path_tool->draw & PATH_TOOL_REDRAW_ACTIVE) if (path_tool->draw & PATH_TOOL_REDRAW_ACTIVE)
{ draw = (segment->flags & SEGMENT_ACTIVE || (segment->next && segment->next->flags & SEGMENT_ACTIVE));
if (segment->flags & SEGMENT_ACTIVE || (segment->next && segment->next->flags & SEGMENT_ACTIVE))
draw=1;
else
draw=0;
}
if (segment && draw) if (segment && draw)
{ {
@ -880,8 +1336,10 @@ path_tool_draw_helper (Path *path, PathCurve *curve, PathSegment * segment, gpoi
gdk_draw_line (core->win, core->gc, x1, y1, x2, y2); gdk_draw_line (core->win, core->gc, x1, y1, x2, y2);
} }
} }
#ifdef PATH_TOOL_DEBUG
else if (!segment) else if (!segment)
fprintf(stderr, "path_tool_draw_segment: no segment to draw\n"); fprintf(stderr, "path_tool_draw_segment: no segment to draw\n");
#endif PATH_TOOL_DEBUG
} }
static void static void
@ -892,11 +1350,14 @@ path_tool_draw (Tool *tool)
PathTool * path_tool; PathTool * path_tool;
PathCurve * cur_curve; PathCurve * cur_curve;
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "path_tool_draw\n"); fprintf (stderr, "path_tool_draw\n");
#endif PATH_TOOL_DEBUG
gdisp = tool->gdisp_ptr; gdisp = tool->gdisp_ptr;
path_tool = tool->private; path_tool = tool->private;
cur_path = path_tool->cur_path; cur_path = path_tool->cur_path;
path_traverse_path (cur_path, NULL, path_tool_draw_helper, NULL, tool); path_traverse_path (cur_path, NULL, path_tool_draw_helper, NULL, tool);
} }

View File

@ -40,45 +40,46 @@ typedef enum { SEGMENT_LINE, SEGMENT_BEZIER } SegmentType;
typedef struct _path_segment PathSegment; typedef struct _path_segment PathSegment;
typedef struct _path_curve PathCurve;
typedef struct _path Path;
typedef struct _path_tool PathTool;
struct _path_segment struct _path_segment
{ {
SegmentType type; /* What type of segment */ SegmentType type; /* What type of segment */
gdouble x, y; /* location of starting-point in image space */ gdouble x, y; /* location of starting-point in image space */
gpointer data; /* Additional data, dependant of segment-type */
guint32 flags; /* Various Flags: Is the Segment active? */ guint32 flags; /* Various Flags: Is the Segment active? */
PathCurve *parent; /* the parent Curve */
PathSegment *next; /* Next Segment or NULL */ PathSegment *next; /* Next Segment or NULL */
PathSegment *prev; /* Previous Segment or NULL */ PathSegment *prev; /* Previous Segment or NULL */
gpointer data; /* Additional data, dependant of segment-type */
}; };
typedef struct _path_curve PathCurve;
struct _path_curve struct _path_curve
{ {
PathSegment * segments; /* The segments of the curve */ PathSegment * segments; /* The segments of the curve */
PathSegment * cur_segment; /* the current segment */ PathSegment * cur_segment; /* the current segment */
Path * parent; /* the parent Path */
PathCurve * next; /* Next Curve or NULL */ PathCurve * next; /* Next Curve or NULL */
PathCurve * prev; /* Previous Curve or NULL */ PathCurve * prev; /* Previous Curve or NULL */
}; };
typedef struct _path Path;
struct _path struct _path
{ {
PathCurve * curves; /* the curves */ PathCurve * curves; /* the curves */
PathCurve * cur_curve; /* the current curve */ PathCurve * cur_curve; /* the current curve */
GString * name; /* the name of the path */ GString * name; /* the name of the path */
guint32 state; /* is the path locked? */ guint32 state; /* is the path locked? */
PathTool * path_tool; /* The parent Path Tool */
}; };
typedef struct _path_tool PathTool;
struct _path_tool struct _path_tool
{ {
gint click_pos; /* where did the user click? */ gint click_pos; /* where did the user click? */
@ -90,6 +91,14 @@ struct _path_tool
PathCurve *click_curve; /* was the click? */ PathCurve *click_curve; /* was the click? */
PathSegment *click_segment; PathSegment *click_segment;
gint active_count; /* How many segments are active? */
/*
* WARNING: single_active_segment may contain non NULL Values
* which point to the nirvana. But they are important!
* The pointer is garantueed to be valid, when active_count==1
*/
PathSegment *single_active_segment; /* The only active segment */
gint state; /* state of tool */ gint state; /* state of tool */
gint draw; /* all or part */ gint draw; /* all or part */
DrawCore *core; /* Core drawing object */ DrawCore *core; /* Core drawing object */

View File

@ -1004,3 +1004,34 @@ static char *xinput_airbrush_bits [] =
"......................" "......................"
}; };
/* GIMP icon image format -- S. Kimball, P. Mattis */
/* Image name: path_tool */
#define path_tool_width 22
#define path_tool_height 22
static char *path_tool_bits [] =
{
"......................",
"......aaa.............",
"......ahae............",
"......aaae............",
".......ee..aaae.......",
"......a..aae..aae.....",
"......e.a.......ae....",
".....a.a.........aa...",
"......a.........aaaa..",
"....aa..........aaaae.",
".....a..a........aaee.",
"...aa....aa.......ee..",
"..aae....aaaa.........",
".ahha.....aaaa........",
".ahhae....aaa.........",
"..aaee.....a.a........",
"..aee.........a.......",
"..a...................",
"..a...................",
"..a...................",
"..a...................",
"......................"
};

View File

@ -520,7 +520,7 @@ ToolInfo tool_info[] =
26, 26,
N_("/Tools/Path"), N_("/Tools/Path"),
"", "",
(char **) measure_bits, (char **) path_tool_bits,
N_("Manipulate paths"), N_("Manipulate paths"),
"ContextHelp/path", "ContextHelp/path",
PATH_TOOL, PATH_TOOL,

View File

@ -29,6 +29,8 @@
* segments between two anchors. * segments between two anchors.
*/ */
#undef PATH_TOOL_DEBUG
#include <math.h> #include <math.h>
/* #include "appenv.h" /* #include "appenv.h"
*/ */
@ -38,7 +40,9 @@
#include "path_tool.h" #include "path_tool.h"
#include "path_toolP.h" #include "path_toolP.h"
#ifdef PATH_TOOL_DEBUG
#include <stdio.h> #include <stdio.h>
#endif PATH_TOOL_DEBUG
#include "libgimp/gimpintl.h" #include "libgimp/gimpintl.h"
@ -68,15 +72,18 @@ static gdouble path_locate_point (Path *, PathCurve **, PathSegment *
/* Tools to manipulate paths, curves, segments */ /* Tools to manipulate paths, curves, segments */
static PathCurve * path_add_curve (Path *, gint, gint); static PathCurve * path_add_curve (Path *, gint, gint);
static inline PathSegment * path_append_segment (Path *, PathCurve *, SegmentType, gint, gint); static PathSegment * path_append_segment (Path *, PathCurve *, SegmentType, gint, gint);
static PathSegment * path_prepend_segment (Path *, PathCurve *, SegmentType, gint, gint); static PathSegment * path_prepend_segment (Path *, PathCurve *, SegmentType, gint, gint);
static PathSegment * path_split_segment (PathSegment *, gdouble); static PathSegment * path_split_segment (PathSegment *, gdouble);
static void path_join_curves (PathSegment *, PathSegment *);
static void path_flip_curve (PathCurve *);
static void path_free_path (Path *); static void path_free_path (Path *);
static void path_free_curve (PathCurve *); static void path_free_curve (PathCurve *);
static void path_free_segment (PathSegment *); static void path_free_segment (PathSegment *);
static void path_delete_segment (PathSegment *);
static void path_print (Path *); static void path_print (Path *);
static void path_offset_active (Path *, gdouble, gdouble); static void path_offset_active (Path *, gdouble, gdouble);
static void path_clear_active (Path *, PathCurve *, PathSegment *); static void path_set_flags (PathTool *, Path *, PathCurve *, PathSegment *, guint32, guint32);
/* High level image-manipulation functions */ /* High level image-manipulation functions */
@ -116,8 +123,9 @@ static ToolOptions *path_options = NULL;
*/ */
/* /*
* These functions are for applying a function over a complete path/curve/segment * These functions are for applying a function over a complete
* they can pass information to each other with a arbitrary data structure * path/curve/segment. They can pass information to each other
* with a arbitrary data structure
* *
* The idea behind the three different functions is: * The idea behind the three different functions is:
* if pathfunc != NULL * if pathfunc != NULL
@ -176,7 +184,9 @@ path_traverse_curve (Path *path, PathCurve *curve, CurveTraverseFunc curvefunc,
static void static void
path_traverse_segment (Path *path, PathCurve *curve, PathSegment *segment, SegmentTraverseFunc function, gpointer data) path_traverse_segment (Path *path, PathCurve *curve, PathSegment *segment, SegmentTraverseFunc function, gpointer data)
{ {
#ifdef PATH_TOOL_DEBUG
fprintf(stderr, "path_traverse_segment\n"); fprintf(stderr, "path_traverse_segment\n");
#endif PATH_TOOL_DEBUG
/* Something like: /* Something like:
* for i = 1 to subsamples { * for i = 1 to subsamples {
@ -190,34 +200,48 @@ path_traverse_segment (Path *path, PathCurve *curve, PathSegment *segment, Segme
* Helper functions for manipulating the data-structures: * Helper functions for manipulating the data-structures:
*/ */
static PathCurve * path_add_curve (Path * cur_path, gint x, gint y) static PathCurve *path_add_curve (Path * cur_path, gint x, gint y)
{ {
PathCurve * tmp = cur_path->curves; PathCurve * tmp = cur_path->curves;
PathCurve * new_curve; PathCurve * new_curve = NULL;
#ifdef PATH_TOOL_DEBUG
fprintf(stderr, "path_add_curve\n"); fprintf(stderr, "path_add_curve\n");
#endif PATH_TOOL_DEBUG
new_curve = g_new (PathCurve, 1); if (cur_path) {
new_curve = g_new (PathCurve, 1);
new_curve->next = tmp; new_curve->parent = cur_path;
new_curve->prev = NULL; new_curve->next = tmp;
new_curve->cur_segment = NULL; new_curve->prev = NULL;
new_curve->segments = NULL; new_curve->cur_segment = NULL;
new_curve->segments = NULL;
if (tmp) tmp->prev = new_curve; if (tmp) tmp->prev = new_curve;
cur_path->curves = cur_path->cur_curve = new_curve; cur_path->curves = cur_path->cur_curve = new_curve;
new_curve->segments = path_append_segment (cur_path, new_curve, SEGMENT_LINE, x, y); new_curve->segments = path_prepend_segment (cur_path, new_curve, SEGMENT_LINE, 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; return new_curve;
} }
static inline PathSegment * path_append_segment (Path * cur_path, PathCurve * cur_curve, SegmentType type, gint x, gint y) static PathSegment * path_append_segment (Path * cur_path, PathCurve * cur_curve, SegmentType type, gint x, gint y)
{ {
PathSegment * tmp = cur_curve->segments; PathSegment * tmp = cur_curve->segments;
PathSegment * new_segment = NULL; PathSegment * new_segment = NULL;
#ifdef PATH_TOOL_DEBUG
fprintf(stderr, "path_append_segment\n");
#endif PATH_TOOL_DEBUG
if (cur_curve) { if (cur_curve) {
tmp = cur_curve->segments; tmp = cur_curve->segments;
while (tmp && tmp->next && tmp->next != cur_curve->segments) { while (tmp && tmp->next && tmp->next != cur_curve->segments) {
@ -230,32 +254,239 @@ static inline PathSegment * path_append_segment (Path * cur_path, PathCurve * c
new_segment->type = type; new_segment->type = type;
new_segment->x = x; new_segment->x = x;
new_segment->y = y; new_segment->y = y;
new_segment->flags = SEGMENT_ACTIVE; new_segment->flags = 0;
new_segment->parent = cur_curve;
new_segment->next = NULL; new_segment->next = NULL;
new_segment->prev = tmp; new_segment->prev = tmp;
new_segment->data = NULL; new_segment->data = NULL;
if (tmp) if (tmp)
{
tmp->next = new_segment; tmp->next = new_segment;
}
cur_curve->cur_segment = new_segment; cur_curve->cur_segment = new_segment;
} }
#ifdef PATH_TOOL_DEBUG
else else
fprintf(stderr, "Fatal Error: path_append_segment called with a closed curve\n"); fprintf(stderr, "Fatal Error: path_append_segment called with a closed curve\n");
#endif PATH_TOOL_DEBUG
} }
#ifdef PATH_TOOL_DEBUG
else else
fprintf(stderr, "Fatal Error: path_append_segment called without valid curve\n"); fprintf(stderr, "Fatal Error: path_append_segment called without valid curve\n");
#endif PATH_TOOL_DEBUG
return new_segment; return new_segment;
} }
/* static PathSegment * path_prepend_segment (Path *, PathCurve *, gint, gint); static PathSegment * path_prepend_segment (Path * cur_path, PathCurve * cur_curve, SegmentType type, gint x, gint y)
* static PathSegment * path_split_segment (PathSegment *, gdouble); {
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;
}
#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;
}
/* static PathSegment * path_split_segment (PathSegment *, gdouble);
*/ */
/*
* Join two arbitrary endpoints and free the parent from the second
* segment, if it differs from the first parents.
*/
static 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;
}
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;
}
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;
}
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "Cant join these curves yet...\n");
return;
#endif PATH_TOOL_DEBUG
}
/*
* This function reverses the order of the anchors. This is
* necessary for some joining operations.
*/
static 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;
}
tmp = tmp->next;
}
}
static void static void
path_free_path (Path * path) path_free_path (Path * path)
{ {
@ -283,13 +514,17 @@ path_free_curve (PathCurve *curve)
if (curve) if (curve)
{ {
tmp2 = curve->segments; tmp2 = curve->segments;
g_free(curve);
/* break closed curves */
if (tmp2 && tmp2->prev)
tmp2->prev->next = NULL;
while ((tmp1 = tmp2) != NULL) while ((tmp1 = tmp2) != NULL)
{ {
tmp2 = tmp1->next; tmp2 = tmp1->next;
path_free_segment (tmp1); path_free_segment (tmp1);
} }
g_free(curve);
} }
} }
@ -298,12 +533,62 @@ path_free_segment (PathSegment *segment)
{ {
if (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);
if (segment->data) if (segment->data)
g_free(segment->data); g_free(segment->data);
g_free (segment); g_free (segment);
} }
} }
static 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);
}
}
static 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
*/
}
}
/* /*
@ -336,7 +621,9 @@ path_tool_button_press (Tool *tool,
gint grab_pointer=0; gint grab_pointer=0;
gint x, y, halfwidth, dummy; gint x, y, halfwidth, dummy;
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "path_tool_button_press\n"); fprintf (stderr, "path_tool_button_press\n");
#endif PATH_TOOL_DEBUG
gdisp = (GDisplay *) gdisp_ptr; gdisp = (GDisplay *) gdisp_ptr;
path_tool = (PathTool *) tool->private; path_tool = (PathTool *) tool->private;
@ -344,7 +631,9 @@ path_tool_button_press (Tool *tool,
/* Transform window-coordinates to canvas-coordinates */ /* Transform window-coordinates to canvas-coordinates */
gdisplay_untransform_coords (gdisp, bevent->x, bevent->y, &x, &y, TRUE, 0); gdisplay_untransform_coords (gdisp, bevent->x, bevent->y, &x, &y, TRUE, 0);
#ifdef PATH_TOOL_DEBUG
fprintf(stderr, "Clickcoordinates %d, %d\n",x,y); fprintf(stderr, "Clickcoordinates %d, %d\n",x,y);
#endif PATH_TOOL_DEBUG
path_tool->click_x = x; path_tool->click_x = x;
path_tool->click_y = y; path_tool->click_y = y;
path_tool->click_modifier = bevent->state; path_tool->click_modifier = bevent->state;
@ -395,20 +684,42 @@ path_tool_button_press_anchor (Tool *tool,
GdkEventButton *bevent, GdkEventButton *bevent,
GDisplay *gdisp) GDisplay *gdisp)
{ {
static guint32 last_click_time=0;
gboolean doubleclick=FALSE;
PathTool *path_tool = tool->private; PathTool *path_tool = tool->private;
Path * cur_path = path_tool->cur_path; Path * cur_path = path_tool->cur_path;
PathSegment *p_sas;
gint grab_pointer; gint grab_pointer;
#ifdef PATH_TOOL_DEBUG
fprintf(stderr, "path_tool_button_press_anchor:\n"); fprintf(stderr, "path_tool_button_press_anchor:\n");
#endif PATH_TOOL_DEBUG
grab_pointer = 1; grab_pointer = 1;
if (!cur_path) { if (!cur_path) {
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "Fatal error: No current Path\n"); fprintf (stderr, "Fatal error: No current Path\n");
#endif PATH_TOOL_DEBUG
return 0; 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); draw_core_pause (path_tool->core, tool);
/* The user pressed on an anchor: /* The user pressed on an anchor:
@ -416,15 +727,75 @@ path_tool_button_press_anchor (Tool *tool,
* + SHIFT toggles the activity of an anchor. * + SHIFT toggles the activity of an anchor.
* if this anchor is at the end of an open curve and the other * if this anchor is at the end of an open curve and the other
* end is active, close the curve. * end is active, close the curve.
*
* Doubleclick (de)activates the whole curve (not Path!).
*/ */
if (path_tool->click_modifier & GDK_SHIFT_MASK) p_sas = path_tool->single_active_segment;
path_tool->click_segment->flags ^= SEGMENT_ACTIVE;
else { #ifdef PATH_TOOL_DEBUG
if (!(path_tool->click_segment->flags & SEGMENT_ACTIVE)) fprintf (stderr, "p_sas: %p\n", p_sas);
path_clear_active (cur_path, NULL, NULL); #endif PATH_TOOL_DEBUG
path_tool->click_segment->flags |= SEGMENT_ACTIVE;
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;
}
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);
}
/* Action goes here */ /* Action goes here */
@ -445,35 +816,47 @@ path_tool_button_press_canvas (Tool *tool,
PathSegment * cur_segment; PathSegment * cur_segment;
gint grab_pointer; gint grab_pointer;
#ifdef PATH_TOOL_DEBUG
fprintf(stderr, "path_tool_button_press_canvas:\n"); fprintf(stderr, "path_tool_button_press_canvas:\n");
#endif PATH_TOOL_DEBUG
grab_pointer = 1; grab_pointer = 1;
if (!cur_path) { if (!cur_path) {
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "Fatal error: No current Path\n"); fprintf (stderr, "Fatal error: No current Path\n");
#endif PATH_TOOL_DEBUG
return 0; return 0;
} }
draw_core_pause (path_tool->core, tool); draw_core_pause (path_tool->core, tool);
path_clear_active (cur_path, NULL, NULL); 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;
if (!(cur_curve = cur_path->cur_curve)) { 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_LINE, path_tool->click_x, path_tool->click_y);
else
cur_curve->cur_segment = path_prepend_segment(cur_path, cur_curve, SEGMENT_LINE, 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 {
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); cur_path->cur_curve = path_add_curve(cur_path, path_tool->click_x, path_tool->click_y);
draw_core_resume(path_tool->core, tool); path_set_flags (path_tool, cur_path, cur_path->cur_curve, cur_path->cur_curve->segments, SEGMENT_ACTIVE, 0);
return 0;
} }
cur_curve->cur_segment = path_append_segment(cur_path, cur_curve, SEGMENT_LINE, path_tool->click_x, path_tool->click_y);
draw_core_resume(path_tool->core, tool); draw_core_resume(path_tool->core, tool);
return 0; return 0;
} }
static void static void
path_tool_button_release (Tool *tool, path_tool_button_release (Tool *tool,
GdkEventButton *bevent, GdkEventButton *bevent,
@ -482,13 +865,14 @@ path_tool_button_release (Tool *tool,
GDisplay * gdisp; GDisplay * gdisp;
PathTool * path_tool; PathTool * path_tool;
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "path_tool_button_release\n"); fprintf (stderr, "path_tool_button_release\n");
#endif PATH_TOOL_DEBUG
gdisp = (GDisplay *) gdisp_ptr; gdisp = (GDisplay *) gdisp_ptr;
path_tool = (PathTool *) tool->private; path_tool = (PathTool *) tool->private;
path_tool->state &= ~PATH_TOOL_DRAG; path_tool->state &= ~PATH_TOOL_DRAG;
path_tool->state = 0;
gdk_pointer_ungrab (bevent->time); gdk_pointer_ungrab (bevent->time);
gdk_flush (); gdk_flush ();
@ -507,6 +891,8 @@ path_tool_motion (Tool *tool,
GDisplay * gdisp; GDisplay * gdisp;
PathTool * path_tool; PathTool * path_tool;
if (gtk_events_pending()) return;
gdisp = (GDisplay *) gdisp_ptr; gdisp = (GDisplay *) gdisp_ptr;
path_tool = (PathTool *) tool->private; path_tool = (PathTool *) tool->private;
@ -526,39 +912,68 @@ path_tool_motion_anchor (Tool *tool,
GDisplay *gdisp) GDisplay *gdisp)
{ {
PathTool * path_tool; PathTool * path_tool;
gdouble dx, dy; gdouble dx, dy, d;
gint x,y; gint x,y;
static gint lastx = 0; static gint dxsum = 0;
static gint lasty = 0; static gint dysum = 0;
if (gtk_events_pending()) return; /* Is this OK? I want to ignore just the motion-events... */
path_tool = (PathTool *) tool->private; 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)) if (!(path_tool->state & PATH_TOOL_DRAG))
{ {
path_tool->state |= PATH_TOOL_DRAG; path_tool->state |= PATH_TOOL_DRAG;
lastx = path_tool->click_x; dxsum = 0;
lasty = path_tool->click_y; dysum = 0;
} }
gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, TRUE, 0); gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, TRUE, 0);
dx = x - lastx; dx = x - path_tool->click_x - dxsum;
dy = y - lasty; 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; path_tool->draw |= PATH_TOOL_REDRAW_ACTIVE;
draw_core_pause(path_tool->core, tool); draw_core_pause(path_tool->core, tool);
path_offset_active (path_tool->cur_path, dx, dy); path_offset_active (path_tool->cur_path, dx, dy);
dxsum += dx;
dysum += dy;
draw_core_resume (path_tool->core, tool); draw_core_resume (path_tool->core, tool);
path_tool->draw &= ~PATH_TOOL_REDRAW_ACTIVE; path_tool->draw &= ~PATH_TOOL_REDRAW_ACTIVE;
lastx = x;
lasty = y;
} }
@ -571,8 +986,10 @@ path_tool_cursor_update (Tool *tool,
GDisplay *gdisp; GDisplay *gdisp;
gint x, y, halfwidth, dummy, cursor_location; gint x, y, halfwidth, dummy, cursor_location;
#ifdef PATH_TOOL_DEBUG
/* fprintf (stderr, "path_tool_cursor_update\n"); /* fprintf (stderr, "path_tool_cursor_update\n");
*/ */
#endif PATH_TOOL_DEBUG
gdisp = (GDisplay *) gdisp_ptr; gdisp = (GDisplay *) gdisp_ptr;
path_tool = (PathTool *) tool->private; path_tool = (PathTool *) tool->private;
@ -609,7 +1026,9 @@ path_tool_control (Tool *tool,
GDisplay * gdisp; GDisplay * gdisp;
PathTool * path_tool; PathTool * path_tool;
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "path_tool_control\n"); fprintf (stderr, "path_tool_control\n");
#endif PATH_TOOL_DEBUG
gdisp = (GDisplay *) tool->gdisp_ptr; gdisp = (GDisplay *) tool->gdisp_ptr;
path_tool = (PathTool *) tool->private; path_tool = (PathTool *) tool->private;
@ -655,6 +1074,10 @@ tools_new_path_tool (void)
private->click_y = 0; private->click_y = 0;
private->click_halfwidth = 0; private->click_halfwidth = 0;
private->click_modifier = 0; private->click_modifier = 0;
private->active_count = 0;
private->single_active_segment = NULL;
private->state = 0; private->state = 0;
private->draw = PATH_TOOL_REDRAW_ALL; private->draw = PATH_TOOL_REDRAW_ALL;
private->core = draw_core_new (path_tool_draw); private->core = draw_core_new (path_tool_draw);
@ -674,6 +1097,7 @@ tools_new_path_tool (void)
private->cur_path->cur_curve = NULL; private->cur_path->cur_curve = NULL;
private->cur_path->name = g_string_new("Path 0"); private->cur_path->name = g_string_new("Path 0");
private->cur_path->state = 0; private->cur_path->state = 0;
private->cur_path->path_tool = private;
return tool; return tool;
} }
@ -701,7 +1125,7 @@ tools_free_path_tool (Tool *tool)
/************************************************************** /**************************************************************
* Set of tools to determine, if the click was on an anchor * Set of function to determine, if the click was on an anchor
*/ */
typedef struct { typedef struct {
@ -767,7 +1191,7 @@ path_tool_on_anchors (Tool *tool, gint x, gint y, gint halfwidth, Path **ret_pat
/************************************************************** /**************************************************************
* Set of tools to offset all active anchors * Set of function to offset all active anchors
*/ */
typedef struct { typedef struct {
@ -802,34 +1226,70 @@ path_offset_active (Path *path, gdouble dx, gdouble dy)
/************************************************************** /**************************************************************
* Set of tools to set the state of all anchors to inactive * Set of function to set the state of all anchors to inactive
*/ */
typedef struct {
guint32 bits_set;
guint32 bits_clear;
PathTool *path_tool;
} Path_set_flags_type;
/* This is a CurveTraverseFunc */ /* This is a CurveTraverseFunc */
static void static void
path_clear_active_helper (Path *path, PathCurve *curve, PathSegment *segment, gpointer ptr) path_set_flags_helper (Path *path, PathCurve *curve, PathSegment *segment, gpointer ptr)
{ {
gint distance; Path_set_flags_type *tmp = (Path_set_flags_type *) ptr;
guint32 oldflags;
if (segment) {
oldflags = segment->flags;
segment->flags &= ~(tmp->bits_clear);
segment->flags |= tmp->bits_set;
if (segment) /*
segment->flags &= ~SEGMENT_ACTIVE; * 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? */
GPOINTER_TO_UINT(tmp->path_tool->single_active_segment) ^= GPOINTER_TO_UINT(segment);
}
}
} }
static void static void
path_clear_active (Path *path, PathCurve *curve, PathSegment *segment) path_set_flags (PathTool *path_tool, Path *path, PathCurve *curve, PathSegment *segment, guint32 bits_set, guint32 bits_clear)
{ {
fprintf (stderr, "path_clear_active\n"); 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) if (segment)
path_clear_active_helper (path, curve, segment, NULL); path_set_flags_helper (path, curve, segment, tmp);
else if (curve) else if (curve)
path_traverse_curve (path, curve, path_clear_active_helper, NULL, NULL); path_traverse_curve (path, curve, path_set_flags_helper, NULL, tmp);
else if (path) else if (path)
path_traverse_path (path, NULL, path_clear_active_helper, NULL, NULL); path_traverse_path (path, NULL, path_set_flags_helper, NULL, tmp);
g_free (tmp);
} }
/************************************************************** /**************************************************************
* Set of tools to draw the segments to the window * Set of functions to draw the segments to the window
*/ */
/* This is a CurveTraverseFunc */ /* This is a CurveTraverseFunc */
@ -840,10 +1300,13 @@ path_tool_draw_helper (Path *path, PathCurve *curve, PathSegment * segment, gpoi
GDisplay * gdisp; GDisplay * gdisp;
PathTool * path_tool; PathTool * path_tool;
DrawCore * core; DrawCore * core;
gint x1, y1, x2, y2, draw; gint x1, y1, x2, y2;
gboolean draw = TRUE;
if (!tool) { if (!tool) {
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "Fatal Error: path_tool_draw_segment called without valid tool *\n"); fprintf (stderr, "Fatal Error: path_tool_draw_segment called without valid tool *\n");
#endif PATH_TOOL_DEBUG
return; return;
} }
@ -852,15 +1315,8 @@ path_tool_draw_helper (Path *path, PathCurve *curve, PathSegment * segment, gpoi
path_tool = (PathTool *) tool->private; path_tool = (PathTool *) tool->private;
core = path_tool->core; core = path_tool->core;
draw = 1;
if (path_tool->draw & PATH_TOOL_REDRAW_ACTIVE) if (path_tool->draw & PATH_TOOL_REDRAW_ACTIVE)
{ draw = (segment->flags & SEGMENT_ACTIVE || (segment->next && segment->next->flags & SEGMENT_ACTIVE));
if (segment->flags & SEGMENT_ACTIVE || (segment->next && segment->next->flags & SEGMENT_ACTIVE))
draw=1;
else
draw=0;
}
if (segment && draw) if (segment && draw)
{ {
@ -880,8 +1336,10 @@ path_tool_draw_helper (Path *path, PathCurve *curve, PathSegment * segment, gpoi
gdk_draw_line (core->win, core->gc, x1, y1, x2, y2); gdk_draw_line (core->win, core->gc, x1, y1, x2, y2);
} }
} }
#ifdef PATH_TOOL_DEBUG
else if (!segment) else if (!segment)
fprintf(stderr, "path_tool_draw_segment: no segment to draw\n"); fprintf(stderr, "path_tool_draw_segment: no segment to draw\n");
#endif PATH_TOOL_DEBUG
} }
static void static void
@ -892,11 +1350,14 @@ path_tool_draw (Tool *tool)
PathTool * path_tool; PathTool * path_tool;
PathCurve * cur_curve; PathCurve * cur_curve;
#ifdef PATH_TOOL_DEBUG
fprintf (stderr, "path_tool_draw\n"); fprintf (stderr, "path_tool_draw\n");
#endif PATH_TOOL_DEBUG
gdisp = tool->gdisp_ptr; gdisp = tool->gdisp_ptr;
path_tool = tool->private; path_tool = tool->private;
cur_path = path_tool->cur_path; cur_path = path_tool->cur_path;
path_traverse_path (cur_path, NULL, path_tool_draw_helper, NULL, tool); path_traverse_path (cur_path, NULL, path_tool_draw_helper, NULL, tool);
} }

View File

@ -40,45 +40,46 @@ typedef enum { SEGMENT_LINE, SEGMENT_BEZIER } SegmentType;
typedef struct _path_segment PathSegment; typedef struct _path_segment PathSegment;
typedef struct _path_curve PathCurve;
typedef struct _path Path;
typedef struct _path_tool PathTool;
struct _path_segment struct _path_segment
{ {
SegmentType type; /* What type of segment */ SegmentType type; /* What type of segment */
gdouble x, y; /* location of starting-point in image space */ gdouble x, y; /* location of starting-point in image space */
gpointer data; /* Additional data, dependant of segment-type */
guint32 flags; /* Various Flags: Is the Segment active? */ guint32 flags; /* Various Flags: Is the Segment active? */
PathCurve *parent; /* the parent Curve */
PathSegment *next; /* Next Segment or NULL */ PathSegment *next; /* Next Segment or NULL */
PathSegment *prev; /* Previous Segment or NULL */ PathSegment *prev; /* Previous Segment or NULL */
gpointer data; /* Additional data, dependant of segment-type */
}; };
typedef struct _path_curve PathCurve;
struct _path_curve struct _path_curve
{ {
PathSegment * segments; /* The segments of the curve */ PathSegment * segments; /* The segments of the curve */
PathSegment * cur_segment; /* the current segment */ PathSegment * cur_segment; /* the current segment */
Path * parent; /* the parent Path */
PathCurve * next; /* Next Curve or NULL */ PathCurve * next; /* Next Curve or NULL */
PathCurve * prev; /* Previous Curve or NULL */ PathCurve * prev; /* Previous Curve or NULL */
}; };
typedef struct _path Path;
struct _path struct _path
{ {
PathCurve * curves; /* the curves */ PathCurve * curves; /* the curves */
PathCurve * cur_curve; /* the current curve */ PathCurve * cur_curve; /* the current curve */
GString * name; /* the name of the path */ GString * name; /* the name of the path */
guint32 state; /* is the path locked? */ guint32 state; /* is the path locked? */
PathTool * path_tool; /* The parent Path Tool */
}; };
typedef struct _path_tool PathTool;
struct _path_tool struct _path_tool
{ {
gint click_pos; /* where did the user click? */ gint click_pos; /* where did the user click? */
@ -90,6 +91,14 @@ struct _path_tool
PathCurve *click_curve; /* was the click? */ PathCurve *click_curve; /* was the click? */
PathSegment *click_segment; PathSegment *click_segment;
gint active_count; /* How many segments are active? */
/*
* WARNING: single_active_segment may contain non NULL Values
* which point to the nirvana. But they are important!
* The pointer is garantueed to be valid, when active_count==1
*/
PathSegment *single_active_segment; /* The only active segment */
gint state; /* state of tool */ gint state; /* state of tool */
gint draw; /* all or part */ gint draw; /* all or part */
DrawCore *core; /* Core drawing object */ DrawCore *core; /* Core drawing object */

View File

@ -520,7 +520,7 @@ ToolInfo tool_info[] =
26, 26,
N_("/Tools/Path"), N_("/Tools/Path"),
"", "",
(char **) measure_bits, (char **) path_tool_bits,
N_("Manipulate paths"), N_("Manipulate paths"),
"ContextHelp/path", "ContextHelp/path",
PATH_TOOL, PATH_TOOL,