mirror of https://github.com/GNOME/gimp.git
parent
e422b59e59
commit
e56ff58b04
13
ChangeLog
13
ChangeLog
|
@ -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>
|
||||
|
||||
* app/brush_select.c: Include config.h, guard inclusion of
|
||||
|
|
603
app/path_tool.c
603
app/path_tool.c
|
@ -29,6 +29,8 @@
|
|||
* segments between two anchors.
|
||||
*/
|
||||
|
||||
#undef PATH_TOOL_DEBUG
|
||||
|
||||
#include <math.h>
|
||||
/* #include "appenv.h"
|
||||
*/
|
||||
|
@ -38,7 +40,9 @@
|
|||
#include "path_tool.h"
|
||||
#include "path_toolP.h"
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
#include "libgimp/gimpintl.h"
|
||||
|
||||
|
@ -68,15 +72,18 @@ static gdouble path_locate_point (Path *, PathCurve **, PathSegment *
|
|||
/* Tools to manipulate paths, curves, segments */
|
||||
|
||||
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_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_curve (PathCurve *);
|
||||
static void path_free_segment (PathSegment *);
|
||||
static void path_delete_segment (PathSegment *);
|
||||
static void path_print (Path *);
|
||||
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 */
|
||||
|
||||
|
@ -116,8 +123,9 @@ static ToolOptions *path_options = NULL;
|
|||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
|
@ -176,7 +184,9 @@ path_traverse_curve (Path *path, PathCurve *curve, CurveTraverseFunc curvefunc,
|
|||
static void
|
||||
path_traverse_segment (Path *path, PathCurve *curve, PathSegment *segment, SegmentTraverseFunc function, gpointer data)
|
||||
{
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf(stderr, "path_traverse_segment\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
/* Something like:
|
||||
* 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:
|
||||
*/
|
||||
|
||||
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 * new_curve;
|
||||
PathCurve * new_curve = NULL;
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
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->prev = NULL;
|
||||
new_curve->cur_segment = NULL;
|
||||
new_curve->segments = NULL;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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 * 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) {
|
||||
|
@ -230,32 +254,239 @@ static inline PathSegment * path_append_segment (Path * cur_path, PathCurve * c
|
|||
new_segment->type = type;
|
||||
new_segment->x = x;
|
||||
new_segment->y = y;
|
||||
new_segment->flags = SEGMENT_ACTIVE;
|
||||
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;
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
/* static PathSegment * path_prepend_segment (Path *, PathCurve *, gint, gint);
|
||||
* static PathSegment * path_split_segment (PathSegment *, gdouble);
|
||||
static PathSegment * path_prepend_segment (Path * cur_path, PathCurve * cur_curve, SegmentType type, gint x, gint y)
|
||||
{
|
||||
PathSegment * tmp = cur_curve->segments;
|
||||
PathSegment * new_segment = NULL;
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf(stderr, "path_prepend_segment\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
if (cur_curve) {
|
||||
tmp = cur_curve->segments;
|
||||
|
||||
if (tmp == NULL || tmp->prev == NULL) {
|
||||
new_segment = g_new (PathSegment, 1);
|
||||
|
||||
new_segment->type = type;
|
||||
new_segment->x = x;
|
||||
new_segment->y = y;
|
||||
new_segment->flags = 0;
|
||||
new_segment->parent = cur_curve;
|
||||
new_segment->next = tmp;
|
||||
new_segment->prev = NULL;
|
||||
new_segment->data = NULL;
|
||||
|
||||
if (tmp)
|
||||
tmp->prev = new_segment;
|
||||
|
||||
cur_curve->segments = new_segment;
|
||||
cur_curve->cur_segment = new_segment;
|
||||
}
|
||||
#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
|
||||
path_free_path (Path * path)
|
||||
{
|
||||
|
@ -283,13 +514,17 @@ path_free_curve (PathCurve *curve)
|
|||
if (curve)
|
||||
{
|
||||
tmp2 = curve->segments;
|
||||
g_free(curve);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,12 +533,62 @@ path_free_segment (PathSegment *segment)
|
|||
{
|
||||
if (segment)
|
||||
{
|
||||
/* Clear the active flag to keep path_tool->single_active_segment consistent */
|
||||
path_set_flags (segment->parent->parent->path_tool, segment->parent->parent,
|
||||
segment->parent, segment, 0, SEGMENT_ACTIVE);
|
||||
if (segment->data)
|
||||
g_free(segment->data);
|
||||
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 x, y, halfwidth, dummy;
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf (stderr, "path_tool_button_press\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
gdisp = (GDisplay *) gdisp_ptr;
|
||||
path_tool = (PathTool *) tool->private;
|
||||
|
@ -344,7 +631,9 @@ path_tool_button_press (Tool *tool,
|
|||
|
||||
/* 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;
|
||||
|
@ -395,20 +684,42 @@ path_tool_button_press_anchor (Tool *tool,
|
|||
GdkEventButton *bevent,
|
||||
GDisplay *gdisp)
|
||||
{
|
||||
static guint32 last_click_time=0;
|
||||
gboolean doubleclick=FALSE;
|
||||
PathTool *path_tool = tool->private;
|
||||
|
||||
Path * cur_path = path_tool->cur_path;
|
||||
PathSegment *p_sas;
|
||||
gint grab_pointer;
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf(stderr, "path_tool_button_press_anchor:\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
grab_pointer = 1;
|
||||
|
||||
if (!cur_path) {
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf (stderr, "Fatal error: No current Path\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to determine, if this was a doubleclick for ourself, because
|
||||
* disp_callback.c ignores the GDK_[23]BUTTON_EVENT's and adding them to
|
||||
* the switch statement confuses some tools.
|
||||
*/
|
||||
if (bevent->time - last_click_time < 250) {
|
||||
doubleclick=TRUE;
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf (stderr, "Doppelclick!\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
} else
|
||||
doubleclick=FALSE;
|
||||
last_click_time = bevent->time;
|
||||
|
||||
|
||||
draw_core_pause (path_tool->core, tool);
|
||||
|
||||
/* The user pressed on an anchor:
|
||||
|
@ -416,15 +727,75 @@ path_tool_button_press_anchor (Tool *tool,
|
|||
* + 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!).
|
||||
*/
|
||||
|
||||
if (path_tool->click_modifier & GDK_SHIFT_MASK)
|
||||
path_tool->click_segment->flags ^= SEGMENT_ACTIVE;
|
||||
else {
|
||||
if (!(path_tool->click_segment->flags & SEGMENT_ACTIVE))
|
||||
path_clear_active (cur_path, NULL, NULL);
|
||||
path_tool->click_segment->flags |= SEGMENT_ACTIVE;
|
||||
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;
|
||||
}
|
||||
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 */
|
||||
|
||||
|
@ -445,35 +816,47 @@ path_tool_button_press_canvas (Tool *tool,
|
|||
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);
|
||||
|
||||
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);
|
||||
draw_core_resume(path_tool->core, tool);
|
||||
return 0;
|
||||
path_set_flags (path_tool, cur_path, cur_path->cur_curve, cur_path->cur_curve->segments, SEGMENT_ACTIVE, 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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
path_tool_button_release (Tool *tool,
|
||||
GdkEventButton *bevent,
|
||||
|
@ -482,13 +865,14 @@ path_tool_button_release (Tool *tool,
|
|||
GDisplay * gdisp;
|
||||
PathTool * path_tool;
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf (stderr, "path_tool_button_release\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
gdisp = (GDisplay *) gdisp_ptr;
|
||||
path_tool = (PathTool *) tool->private;
|
||||
|
||||
path_tool->state &= ~PATH_TOOL_DRAG;
|
||||
path_tool->state = 0;
|
||||
|
||||
gdk_pointer_ungrab (bevent->time);
|
||||
gdk_flush ();
|
||||
|
@ -507,6 +891,8 @@ path_tool_motion (Tool *tool,
|
|||
GDisplay * gdisp;
|
||||
PathTool * path_tool;
|
||||
|
||||
if (gtk_events_pending()) return;
|
||||
|
||||
gdisp = (GDisplay *) gdisp_ptr;
|
||||
path_tool = (PathTool *) tool->private;
|
||||
|
||||
|
@ -526,39 +912,68 @@ path_tool_motion_anchor (Tool *tool,
|
|||
GDisplay *gdisp)
|
||||
{
|
||||
PathTool * path_tool;
|
||||
gdouble dx, dy;
|
||||
gdouble dx, dy, d;
|
||||
gint x,y;
|
||||
static gint lastx = 0;
|
||||
static gint lasty = 0;
|
||||
|
||||
if (gtk_events_pending()) return; /* Is this OK? I want to ignore just the motion-events... */
|
||||
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;
|
||||
lastx = path_tool->click_x;
|
||||
lasty = path_tool->click_y;
|
||||
dxsum = 0;
|
||||
dysum = 0;
|
||||
}
|
||||
|
||||
gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, TRUE, 0);
|
||||
|
||||
dx = x - lastx;
|
||||
dy = y - lasty;
|
||||
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;
|
||||
|
||||
lastx = x;
|
||||
lasty = y;
|
||||
}
|
||||
|
||||
|
||||
|
@ -571,8 +986,10 @@ path_tool_cursor_update (Tool *tool,
|
|||
GDisplay *gdisp;
|
||||
gint x, y, halfwidth, dummy, cursor_location;
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
/* fprintf (stderr, "path_tool_cursor_update\n");
|
||||
*/
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
gdisp = (GDisplay *) gdisp_ptr;
|
||||
path_tool = (PathTool *) tool->private;
|
||||
|
@ -609,7 +1026,9 @@ path_tool_control (Tool *tool,
|
|||
GDisplay * gdisp;
|
||||
PathTool * path_tool;
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf (stderr, "path_tool_control\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
gdisp = (GDisplay *) tool->gdisp_ptr;
|
||||
path_tool = (PathTool *) tool->private;
|
||||
|
@ -655,6 +1074,10 @@ tools_new_path_tool (void)
|
|||
private->click_y = 0;
|
||||
private->click_halfwidth = 0;
|
||||
private->click_modifier = 0;
|
||||
|
||||
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);
|
||||
|
@ -674,6 +1097,7 @@ tools_new_path_tool (void)
|
|||
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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 */
|
||||
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
|
||||
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)
|
||||
path_clear_active_helper (path, curve, segment, NULL);
|
||||
path_set_flags_helper (path, curve, segment, tmp);
|
||||
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)
|
||||
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 */
|
||||
|
@ -840,10 +1300,13 @@ path_tool_draw_helper (Path *path, PathCurve *curve, PathSegment * segment, gpoi
|
|||
GDisplay * gdisp;
|
||||
PathTool * path_tool;
|
||||
DrawCore * core;
|
||||
gint x1, y1, x2, y2, draw;
|
||||
gint x1, y1, x2, y2;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -852,15 +1315,8 @@ path_tool_draw_helper (Path *path, PathCurve *curve, PathSegment * segment, gpoi
|
|||
path_tool = (PathTool *) tool->private;
|
||||
core = path_tool->core;
|
||||
|
||||
draw = 1;
|
||||
|
||||
if (path_tool->draw & PATH_TOOL_REDRAW_ACTIVE)
|
||||
{
|
||||
if (segment->flags & SEGMENT_ACTIVE || (segment->next && segment->next->flags & SEGMENT_ACTIVE))
|
||||
draw=1;
|
||||
else
|
||||
draw=0;
|
||||
}
|
||||
draw = (segment->flags & SEGMENT_ACTIVE || (segment->next && segment->next->flags & SEGMENT_ACTIVE));
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
else if (!segment)
|
||||
fprintf(stderr, "path_tool_draw_segment: no segment to draw\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -892,11 +1350,14 @@ path_tool_draw (Tool *tool)
|
|||
PathTool * path_tool;
|
||||
PathCurve * cur_curve;
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf (stderr, "path_tool_draw\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
gdisp = tool->gdisp_ptr;
|
||||
path_tool = tool->private;
|
||||
cur_path = path_tool->cur_path;
|
||||
|
||||
path_traverse_path (cur_path, NULL, path_tool_draw_helper, NULL, tool);
|
||||
|
||||
}
|
||||
|
|
|
@ -40,45 +40,46 @@ typedef enum { SEGMENT_LINE, SEGMENT_BEZIER } SegmentType;
|
|||
|
||||
|
||||
typedef struct _path_segment PathSegment;
|
||||
typedef struct _path_curve PathCurve;
|
||||
typedef struct _path Path;
|
||||
|
||||
typedef struct _path_tool PathTool;
|
||||
|
||||
struct _path_segment
|
||||
{
|
||||
SegmentType type; /* What type of segment */
|
||||
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? */
|
||||
|
||||
PathCurve *parent; /* the parent Curve */
|
||||
PathSegment *next; /* Next 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
|
||||
{
|
||||
PathSegment * segments; /* The segments of the curve */
|
||||
PathSegment * cur_segment; /* the current segment */
|
||||
Path * parent; /* the parent Path */
|
||||
PathCurve * next; /* Next Curve or NULL */
|
||||
PathCurve * prev; /* Previous Curve or NULL */
|
||||
};
|
||||
|
||||
|
||||
typedef struct _path Path;
|
||||
|
||||
struct _path
|
||||
{
|
||||
PathCurve * curves; /* the curves */
|
||||
PathCurve * cur_curve; /* the current curve */
|
||||
GString * name; /* the name of the path */
|
||||
guint32 state; /* is the path locked? */
|
||||
PathTool * path_tool; /* The parent Path Tool */
|
||||
};
|
||||
|
||||
|
||||
typedef struct _path_tool PathTool;
|
||||
|
||||
struct _path_tool
|
||||
{
|
||||
gint click_pos; /* where did the user click? */
|
||||
|
@ -90,6 +91,14 @@ struct _path_tool
|
|||
PathCurve *click_curve; /* was the click? */
|
||||
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 draw; /* all or part */
|
||||
DrawCore *core; /* Core drawing object */
|
||||
|
|
|
@ -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...................",
|
||||
"......................"
|
||||
};
|
||||
|
|
|
@ -520,7 +520,7 @@ ToolInfo tool_info[] =
|
|||
26,
|
||||
N_("/Tools/Path"),
|
||||
"",
|
||||
(char **) measure_bits,
|
||||
(char **) path_tool_bits,
|
||||
N_("Manipulate paths"),
|
||||
"ContextHelp/path",
|
||||
PATH_TOOL,
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
* segments between two anchors.
|
||||
*/
|
||||
|
||||
#undef PATH_TOOL_DEBUG
|
||||
|
||||
#include <math.h>
|
||||
/* #include "appenv.h"
|
||||
*/
|
||||
|
@ -38,7 +40,9 @@
|
|||
#include "path_tool.h"
|
||||
#include "path_toolP.h"
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
#include "libgimp/gimpintl.h"
|
||||
|
||||
|
@ -68,15 +72,18 @@ static gdouble path_locate_point (Path *, PathCurve **, PathSegment *
|
|||
/* Tools to manipulate paths, curves, segments */
|
||||
|
||||
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_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_curve (PathCurve *);
|
||||
static void path_free_segment (PathSegment *);
|
||||
static void path_delete_segment (PathSegment *);
|
||||
static void path_print (Path *);
|
||||
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 */
|
||||
|
||||
|
@ -116,8 +123,9 @@ static ToolOptions *path_options = NULL;
|
|||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
|
@ -176,7 +184,9 @@ path_traverse_curve (Path *path, PathCurve *curve, CurveTraverseFunc curvefunc,
|
|||
static void
|
||||
path_traverse_segment (Path *path, PathCurve *curve, PathSegment *segment, SegmentTraverseFunc function, gpointer data)
|
||||
{
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf(stderr, "path_traverse_segment\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
/* Something like:
|
||||
* 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:
|
||||
*/
|
||||
|
||||
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 * new_curve;
|
||||
PathCurve * new_curve = NULL;
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
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->prev = NULL;
|
||||
new_curve->cur_segment = NULL;
|
||||
new_curve->segments = NULL;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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 * 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) {
|
||||
|
@ -230,32 +254,239 @@ static inline PathSegment * path_append_segment (Path * cur_path, PathCurve * c
|
|||
new_segment->type = type;
|
||||
new_segment->x = x;
|
||||
new_segment->y = y;
|
||||
new_segment->flags = SEGMENT_ACTIVE;
|
||||
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;
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
/* static PathSegment * path_prepend_segment (Path *, PathCurve *, gint, gint);
|
||||
* static PathSegment * path_split_segment (PathSegment *, gdouble);
|
||||
static PathSegment * path_prepend_segment (Path * cur_path, PathCurve * cur_curve, SegmentType type, gint x, gint y)
|
||||
{
|
||||
PathSegment * tmp = cur_curve->segments;
|
||||
PathSegment * new_segment = NULL;
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf(stderr, "path_prepend_segment\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
if (cur_curve) {
|
||||
tmp = cur_curve->segments;
|
||||
|
||||
if (tmp == NULL || tmp->prev == NULL) {
|
||||
new_segment = g_new (PathSegment, 1);
|
||||
|
||||
new_segment->type = type;
|
||||
new_segment->x = x;
|
||||
new_segment->y = y;
|
||||
new_segment->flags = 0;
|
||||
new_segment->parent = cur_curve;
|
||||
new_segment->next = tmp;
|
||||
new_segment->prev = NULL;
|
||||
new_segment->data = NULL;
|
||||
|
||||
if (tmp)
|
||||
tmp->prev = new_segment;
|
||||
|
||||
cur_curve->segments = new_segment;
|
||||
cur_curve->cur_segment = new_segment;
|
||||
}
|
||||
#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
|
||||
path_free_path (Path * path)
|
||||
{
|
||||
|
@ -283,13 +514,17 @@ path_free_curve (PathCurve *curve)
|
|||
if (curve)
|
||||
{
|
||||
tmp2 = curve->segments;
|
||||
g_free(curve);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,12 +533,62 @@ path_free_segment (PathSegment *segment)
|
|||
{
|
||||
if (segment)
|
||||
{
|
||||
/* Clear the active flag to keep path_tool->single_active_segment consistent */
|
||||
path_set_flags (segment->parent->parent->path_tool, segment->parent->parent,
|
||||
segment->parent, segment, 0, SEGMENT_ACTIVE);
|
||||
if (segment->data)
|
||||
g_free(segment->data);
|
||||
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 x, y, halfwidth, dummy;
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf (stderr, "path_tool_button_press\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
gdisp = (GDisplay *) gdisp_ptr;
|
||||
path_tool = (PathTool *) tool->private;
|
||||
|
@ -344,7 +631,9 @@ path_tool_button_press (Tool *tool,
|
|||
|
||||
/* 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;
|
||||
|
@ -395,20 +684,42 @@ path_tool_button_press_anchor (Tool *tool,
|
|||
GdkEventButton *bevent,
|
||||
GDisplay *gdisp)
|
||||
{
|
||||
static guint32 last_click_time=0;
|
||||
gboolean doubleclick=FALSE;
|
||||
PathTool *path_tool = tool->private;
|
||||
|
||||
Path * cur_path = path_tool->cur_path;
|
||||
PathSegment *p_sas;
|
||||
gint grab_pointer;
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf(stderr, "path_tool_button_press_anchor:\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
grab_pointer = 1;
|
||||
|
||||
if (!cur_path) {
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf (stderr, "Fatal error: No current Path\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to determine, if this was a doubleclick for ourself, because
|
||||
* disp_callback.c ignores the GDK_[23]BUTTON_EVENT's and adding them to
|
||||
* the switch statement confuses some tools.
|
||||
*/
|
||||
if (bevent->time - last_click_time < 250) {
|
||||
doubleclick=TRUE;
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf (stderr, "Doppelclick!\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
} else
|
||||
doubleclick=FALSE;
|
||||
last_click_time = bevent->time;
|
||||
|
||||
|
||||
draw_core_pause (path_tool->core, tool);
|
||||
|
||||
/* The user pressed on an anchor:
|
||||
|
@ -416,15 +727,75 @@ path_tool_button_press_anchor (Tool *tool,
|
|||
* + 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!).
|
||||
*/
|
||||
|
||||
if (path_tool->click_modifier & GDK_SHIFT_MASK)
|
||||
path_tool->click_segment->flags ^= SEGMENT_ACTIVE;
|
||||
else {
|
||||
if (!(path_tool->click_segment->flags & SEGMENT_ACTIVE))
|
||||
path_clear_active (cur_path, NULL, NULL);
|
||||
path_tool->click_segment->flags |= SEGMENT_ACTIVE;
|
||||
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;
|
||||
}
|
||||
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 */
|
||||
|
||||
|
@ -445,35 +816,47 @@ path_tool_button_press_canvas (Tool *tool,
|
|||
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);
|
||||
|
||||
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);
|
||||
draw_core_resume(path_tool->core, tool);
|
||||
return 0;
|
||||
path_set_flags (path_tool, cur_path, cur_path->cur_curve, cur_path->cur_curve->segments, SEGMENT_ACTIVE, 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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
path_tool_button_release (Tool *tool,
|
||||
GdkEventButton *bevent,
|
||||
|
@ -482,13 +865,14 @@ path_tool_button_release (Tool *tool,
|
|||
GDisplay * gdisp;
|
||||
PathTool * path_tool;
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf (stderr, "path_tool_button_release\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
gdisp = (GDisplay *) gdisp_ptr;
|
||||
path_tool = (PathTool *) tool->private;
|
||||
|
||||
path_tool->state &= ~PATH_TOOL_DRAG;
|
||||
path_tool->state = 0;
|
||||
|
||||
gdk_pointer_ungrab (bevent->time);
|
||||
gdk_flush ();
|
||||
|
@ -507,6 +891,8 @@ path_tool_motion (Tool *tool,
|
|||
GDisplay * gdisp;
|
||||
PathTool * path_tool;
|
||||
|
||||
if (gtk_events_pending()) return;
|
||||
|
||||
gdisp = (GDisplay *) gdisp_ptr;
|
||||
path_tool = (PathTool *) tool->private;
|
||||
|
||||
|
@ -526,39 +912,68 @@ path_tool_motion_anchor (Tool *tool,
|
|||
GDisplay *gdisp)
|
||||
{
|
||||
PathTool * path_tool;
|
||||
gdouble dx, dy;
|
||||
gdouble dx, dy, d;
|
||||
gint x,y;
|
||||
static gint lastx = 0;
|
||||
static gint lasty = 0;
|
||||
|
||||
if (gtk_events_pending()) return; /* Is this OK? I want to ignore just the motion-events... */
|
||||
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;
|
||||
lastx = path_tool->click_x;
|
||||
lasty = path_tool->click_y;
|
||||
dxsum = 0;
|
||||
dysum = 0;
|
||||
}
|
||||
|
||||
gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, TRUE, 0);
|
||||
|
||||
dx = x - lastx;
|
||||
dy = y - lasty;
|
||||
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;
|
||||
|
||||
lastx = x;
|
||||
lasty = y;
|
||||
}
|
||||
|
||||
|
||||
|
@ -571,8 +986,10 @@ path_tool_cursor_update (Tool *tool,
|
|||
GDisplay *gdisp;
|
||||
gint x, y, halfwidth, dummy, cursor_location;
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
/* fprintf (stderr, "path_tool_cursor_update\n");
|
||||
*/
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
gdisp = (GDisplay *) gdisp_ptr;
|
||||
path_tool = (PathTool *) tool->private;
|
||||
|
@ -609,7 +1026,9 @@ path_tool_control (Tool *tool,
|
|||
GDisplay * gdisp;
|
||||
PathTool * path_tool;
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf (stderr, "path_tool_control\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
gdisp = (GDisplay *) tool->gdisp_ptr;
|
||||
path_tool = (PathTool *) tool->private;
|
||||
|
@ -655,6 +1074,10 @@ tools_new_path_tool (void)
|
|||
private->click_y = 0;
|
||||
private->click_halfwidth = 0;
|
||||
private->click_modifier = 0;
|
||||
|
||||
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);
|
||||
|
@ -674,6 +1097,7 @@ tools_new_path_tool (void)
|
|||
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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 */
|
||||
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
|
||||
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)
|
||||
path_clear_active_helper (path, curve, segment, NULL);
|
||||
path_set_flags_helper (path, curve, segment, tmp);
|
||||
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)
|
||||
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 */
|
||||
|
@ -840,10 +1300,13 @@ path_tool_draw_helper (Path *path, PathCurve *curve, PathSegment * segment, gpoi
|
|||
GDisplay * gdisp;
|
||||
PathTool * path_tool;
|
||||
DrawCore * core;
|
||||
gint x1, y1, x2, y2, draw;
|
||||
gint x1, y1, x2, y2;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -852,15 +1315,8 @@ path_tool_draw_helper (Path *path, PathCurve *curve, PathSegment * segment, gpoi
|
|||
path_tool = (PathTool *) tool->private;
|
||||
core = path_tool->core;
|
||||
|
||||
draw = 1;
|
||||
|
||||
if (path_tool->draw & PATH_TOOL_REDRAW_ACTIVE)
|
||||
{
|
||||
if (segment->flags & SEGMENT_ACTIVE || (segment->next && segment->next->flags & SEGMENT_ACTIVE))
|
||||
draw=1;
|
||||
else
|
||||
draw=0;
|
||||
}
|
||||
draw = (segment->flags & SEGMENT_ACTIVE || (segment->next && segment->next->flags & SEGMENT_ACTIVE));
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
else if (!segment)
|
||||
fprintf(stderr, "path_tool_draw_segment: no segment to draw\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -892,11 +1350,14 @@ path_tool_draw (Tool *tool)
|
|||
PathTool * path_tool;
|
||||
PathCurve * cur_curve;
|
||||
|
||||
#ifdef PATH_TOOL_DEBUG
|
||||
fprintf (stderr, "path_tool_draw\n");
|
||||
#endif PATH_TOOL_DEBUG
|
||||
|
||||
gdisp = tool->gdisp_ptr;
|
||||
path_tool = tool->private;
|
||||
cur_path = path_tool->cur_path;
|
||||
|
||||
path_traverse_path (cur_path, NULL, path_tool_draw_helper, NULL, tool);
|
||||
|
||||
}
|
||||
|
|
|
@ -40,45 +40,46 @@ typedef enum { SEGMENT_LINE, SEGMENT_BEZIER } SegmentType;
|
|||
|
||||
|
||||
typedef struct _path_segment PathSegment;
|
||||
typedef struct _path_curve PathCurve;
|
||||
typedef struct _path Path;
|
||||
|
||||
typedef struct _path_tool PathTool;
|
||||
|
||||
struct _path_segment
|
||||
{
|
||||
SegmentType type; /* What type of segment */
|
||||
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? */
|
||||
|
||||
PathCurve *parent; /* the parent Curve */
|
||||
PathSegment *next; /* Next 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
|
||||
{
|
||||
PathSegment * segments; /* The segments of the curve */
|
||||
PathSegment * cur_segment; /* the current segment */
|
||||
Path * parent; /* the parent Path */
|
||||
PathCurve * next; /* Next Curve or NULL */
|
||||
PathCurve * prev; /* Previous Curve or NULL */
|
||||
};
|
||||
|
||||
|
||||
typedef struct _path Path;
|
||||
|
||||
struct _path
|
||||
{
|
||||
PathCurve * curves; /* the curves */
|
||||
PathCurve * cur_curve; /* the current curve */
|
||||
GString * name; /* the name of the path */
|
||||
guint32 state; /* is the path locked? */
|
||||
PathTool * path_tool; /* The parent Path Tool */
|
||||
};
|
||||
|
||||
|
||||
typedef struct _path_tool PathTool;
|
||||
|
||||
struct _path_tool
|
||||
{
|
||||
gint click_pos; /* where did the user click? */
|
||||
|
@ -90,6 +91,14 @@ struct _path_tool
|
|||
PathCurve *click_curve; /* was the click? */
|
||||
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 draw; /* all or part */
|
||||
DrawCore *core; /* Core drawing object */
|
||||
|
|
|
@ -520,7 +520,7 @@ ToolInfo tool_info[] =
|
|||
26,
|
||||
N_("/Tools/Path"),
|
||||
"",
|
||||
(char **) measure_bits,
|
||||
(char **) path_tool_bits,
|
||||
N_("Manipulate paths"),
|
||||
"ContextHelp/path",
|
||||
PATH_TOOL,
|
||||
|
|
Loading…
Reference in New Issue