home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / path_tool.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-07-01  |  50.5 KB  |  1,911 lines

  1. /* The GIMP -- an image manipulation program
  2.  * 
  3.  * This file Copyright (C) 1999 Simon Budig
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18.  */
  19.  
  20. /*
  21.  * Complete new path-tool by Simon Budig <Simon.Budig@unix-ag.org>
  22.  * 
  23.  * a path manipulation core independent of the underlying formula:
  24.  * implement bezier-curves, intelligent scissors-curves, splines...
  25.  * 
  26.  * A Path is a collection of curves, which are constructed from
  27.  * segments between two anchors.
  28.  */
  29.  
  30. #include <math.h>
  31. /* #include "appenv.h"
  32.  */
  33.  
  34. #include "draw_core.h"
  35. #include "cursorutil.h"
  36. #include "path_tool.h"
  37. #include "path_toolP.h"
  38. #include "path_curves.h"
  39.  
  40. #include "config.h"
  41. #include "libgimp/gimpintl.h"
  42.  
  43. /*
  44.  * Every new curve-type has to have a parameter between 0 and 1, and
  45.  * should go from a starting to a target point.
  46.  */
  47.  
  48.  
  49.  
  50. /* Some defines... */
  51.  
  52. #define PATH_TOOL_WIDTH 8
  53. #define PATH_TOOL_HALFWIDTH 4
  54.  
  55. /*  local function prototypes  */
  56.  
  57.  
  58. /* Small functions to determine coordinates, iterate over path/curve/segment */
  59.  
  60. void    path_segment_get_coordinates (PathSegment *,
  61.                       gdouble,
  62.                       gint *,
  63.                       gint *);
  64. void    path_traverse_path           (Path *,
  65.                       PathTraverseFunc,
  66.                       CurveTraverseFunc,
  67.                       SegmentTraverseFunc,
  68.                       gpointer);
  69. void    path_traverse_curve          (Path *,
  70.                       PathCurve *,
  71.                       CurveTraverseFunc,
  72.                       SegmentTraverseFunc,
  73.                       gpointer);
  74. void    path_traverse_segment        (Path *,
  75.                       PathCurve *,
  76.                       PathSegment *,
  77.                       SegmentTraverseFunc,
  78.                       gpointer);
  79. gdouble path_locate_point            (Path *,
  80.                       PathCurve **,
  81.                       PathSegment **,
  82.                       gint,
  83.                       gint,
  84.                       gint,
  85.                       gint,
  86.                       gint);
  87.  
  88. /* Tools to manipulate paths, curves, segments */
  89.  
  90. PathCurve   * path_add_curve       (Path *,
  91.                     gint,
  92.                     gint);
  93. PathSegment * path_append_segment  (Path *,
  94.                     PathCurve *,
  95.                     SegmentType,
  96.                     gint,
  97.                     gint);
  98. PathSegment * path_prepend_segment (Path *,
  99.                     PathCurve *,
  100.                     SegmentType,
  101.                     gint,
  102.                     gint);
  103. PathSegment * path_split_segment   (PathSegment *,
  104.                     gdouble);
  105. void          path_join_curves     (PathSegment *,
  106.                     PathSegment *);
  107. void          path_flip_curve      (PathCurve *);
  108. void          path_free_path       (Path *);
  109. void          path_free_curve      (PathCurve *);
  110. void          path_free_segment    (PathSegment *);
  111. void          path_delete_segment  (PathSegment *);
  112. void          path_print           (Path *);
  113. void          path_offset_active   (Path *, gdouble, gdouble);
  114. void          path_set_flags       (PathTool *,
  115.                     Path *,
  116.                     PathCurve *,
  117.                     PathSegment *,
  118.                     guint32,
  119.                     guint32);
  120.  
  121. /* High level image-manipulation functions */
  122.  
  123. void path_stroke                   (PathTool *,
  124.                     Path *);
  125. void path_to_selection             (PathTool *,
  126.                     Path *);
  127.  
  128. /* Functions necessary for the tool */
  129.  
  130. void     path_tool_button_press    (Tool *, GdkEventButton *, gpointer);
  131. void     path_tool_button_release  (Tool *, GdkEventButton *, gpointer);
  132. void     path_tool_motion          (Tool *, GdkEventMotion *, gpointer);
  133. void     path_tool_cursor_update   (Tool *, GdkEventMotion *, gpointer);
  134. void     path_tool_control         (Tool *, ToolAction,       gpointer);
  135. void     path_tool_draw            (Tool *);
  136. void     path_tool_draw_curve      (Tool *, PathCurve *);
  137. void     path_tool_draw_segment    (Tool *, PathSegment *);
  138.  
  139. gdouble  path_tool_on_curve        (Tool *, gint, gint, gint,
  140.                     Path**, PathCurve**, PathSegment**);
  141. gboolean path_tool_on_anchors      (Tool *, gint, gint, gint,
  142.                     Path**, PathCurve**, PathSegment**);
  143. gint     path_tool_on_handles      (Tool *, gint, gint, gint,
  144.                             Path **, PathCurve **, PathSegment **);
  145.  
  146. gint path_tool_button_press_canvas (Tool *, GdkEventButton *, GDisplay *);
  147. gint path_tool_button_press_anchor (Tool *, GdkEventButton *, GDisplay *);
  148. gint path_tool_button_press_handle (Tool *, GdkEventButton *, GDisplay *);
  149. gint path_tool_button_press_curve  (Tool *, GdkEventButton *, GDisplay *);
  150. void path_tool_motion_anchor       (Tool *, GdkEventMotion *, GDisplay *);
  151. void path_tool_motion_handle       (Tool *, GdkEventMotion *, GDisplay *);
  152. void path_tool_motion_curve        (Tool *, GdkEventMotion *, GDisplay *);
  153.  
  154.  
  155. /*  the path tool options  */
  156. static ToolOptions *path_options = NULL;
  157.  
  158.  
  159. /* 
  160.  * 
  161.  * 
  162.  * Here we go!
  163.  * 
  164.  * 
  165.  */
  166.  
  167. /*
  168.  * These functions are for applying a function over a complete
  169.  * path/curve/segment. They can pass information to each other
  170.  * with a arbitrary data structure
  171.  *
  172.  * The idea behind the three different functions is:
  173.  *  if pathfunc != NULL
  174.  *     call pathfunc for every curve
  175.  *  else
  176.  *     if curvefunc != NULL
  177.  *        call curvefunc for every segment
  178.  *     else
  179.  *        call segmentfunc for every point
  180.  *
  181.  */
  182.  
  183. void
  184. path_traverse_path (Path *path,
  185.             PathTraverseFunc pathfunc,
  186.             CurveTraverseFunc curvefunc,
  187.             SegmentTraverseFunc segmentfunc,
  188.             gpointer data)
  189. {
  190.    PathCurve *cur_curve;
  191.  
  192.    if (path && path->curves)
  193.    {
  194.       cur_curve = path->curves;
  195.       if (pathfunc)
  196.          do {
  197.             (* pathfunc) (path, cur_curve, data);
  198.             cur_curve = cur_curve->next;
  199.          } while (cur_curve && cur_curve != path->curves);
  200.       else
  201.          do {
  202.             path_traverse_curve (path, cur_curve, curvefunc, segmentfunc, data);
  203.             cur_curve = cur_curve->next;
  204.          } while (cur_curve && cur_curve != path->curves);
  205.    }
  206. }
  207.      
  208.  
  209. void
  210. path_traverse_curve (Path *path,
  211.              PathCurve *curve,
  212.              CurveTraverseFunc curvefunc,
  213.              SegmentTraverseFunc segmentfunc,
  214.              gpointer data)
  215. {
  216.    PathSegment *cur_segment;
  217.  
  218.    if (curve && curve->segments)
  219.    {
  220.       cur_segment = curve->segments;
  221.       if (curvefunc)
  222.          do {
  223.             (* curvefunc) (path, curve, cur_segment, data);
  224.             cur_segment = cur_segment->next;
  225.          } while (cur_segment && cur_segment != curve->segments);
  226.       else
  227.          do {
  228.             path_traverse_segment (path, curve, cur_segment, segmentfunc, data);
  229.             cur_segment = cur_segment->next;
  230.          } while (cur_segment && cur_segment != curve->segments);
  231.    }
  232. }
  233.  
  234. void
  235. path_traverse_segment (Path *path,
  236.                PathCurve *curve,
  237.                PathSegment *segment,
  238.                SegmentTraverseFunc function,
  239.                gpointer data)
  240. {
  241. #ifdef PATH_TOOL_DEBUG
  242.    fprintf(stderr, "path_traverse_segment\n");
  243. #endif PATH_TOOL_DEBUG
  244.  
  245.    /* XXX: here we need path_curve_get_point(s) */
  246.  
  247.    /* Something like:
  248.     * for i = 1 to subsamples {
  249.     *   (x,y) = get_coordinates(i / subsamples)
  250.     *   (* function) (....)
  251.     * }
  252.     */
  253. }
  254.  
  255. /**************************************************************
  256.  * Helper functions for manipulating the data-structures:
  257.  */
  258.  
  259. PathCurve *
  260. path_add_curve (Path * cur_path,
  261.         gint x,
  262.         gint y)
  263. {
  264.    PathCurve * tmp = cur_path->curves;
  265.    PathCurve * new_curve = NULL;
  266.  
  267. #ifdef PATH_TOOL_DEBUG
  268.    fprintf(stderr, "path_add_curve\n");
  269. #endif PATH_TOOL_DEBUG
  270.    
  271.    if (cur_path) {
  272.       new_curve = g_new (PathCurve, 1);
  273.    
  274.       new_curve->parent = cur_path;
  275.       new_curve->next = tmp;
  276.       new_curve->prev = NULL;
  277.       new_curve->cur_segment = NULL;
  278.       new_curve->segments = NULL;
  279.  
  280.       if (tmp) tmp->prev = new_curve;
  281.    
  282.       cur_path->curves = cur_path->cur_curve = new_curve;
  283.    
  284.       new_curve->segments = path_prepend_segment (cur_path, new_curve, SEGMENT_BEZIER, x, y);
  285.    }
  286. #ifdef PATH_TOOL_DEBUG
  287.    else
  288.       fprintf (stderr, "Fatal Error: path_add_curve called without valid path\n");
  289. #endif PATH_TOOL_DEBUG
  290.  
  291.    return new_curve;
  292. }
  293.    
  294.    
  295. PathSegment *
  296. path_append_segment  (Path * cur_path,
  297.               PathCurve * cur_curve,
  298.               SegmentType type,
  299.               gint x,
  300.               gint y)
  301. {
  302.    PathSegment * tmp = cur_curve->segments;
  303.    PathSegment * new_segment = NULL;
  304.    
  305. #ifdef PATH_TOOL_DEBUG
  306.       fprintf(stderr, "path_append_segment\n");
  307. #endif PATH_TOOL_DEBUG
  308.  
  309.    if (cur_curve) {
  310.       tmp = cur_curve->segments;
  311.       while (tmp && tmp->next && tmp->next != cur_curve->segments) {
  312.          tmp = tmp->next;
  313.       }
  314.    
  315.       if (tmp == NULL || tmp->next == NULL) {
  316.          new_segment = g_new (PathSegment, 1);
  317.          
  318.          new_segment->type = type;
  319.          new_segment->x = x;
  320.          new_segment->y = y;
  321.          new_segment->flags = 0;
  322.          new_segment->parent = cur_curve;
  323.          new_segment->next = NULL;
  324.          new_segment->prev = tmp;
  325.          new_segment->data = NULL;
  326.          
  327.          if (tmp) 
  328.             tmp->next = new_segment;
  329.  
  330.          cur_curve->cur_segment = new_segment;
  331.      
  332.      path_curve_init_segment (new_segment);
  333.  
  334.       }
  335. #ifdef PATH_TOOL_DEBUG
  336.       else
  337.          fprintf(stderr, "Fatal Error: path_append_segment called with a closed curve\n");
  338. #endif PATH_TOOL_DEBUG
  339.    }
  340. #ifdef PATH_TOOL_DEBUG
  341.    else
  342.       fprintf(stderr, "Fatal Error: path_append_segment called without valid curve\n");
  343. #endif PATH_TOOL_DEBUG
  344.    
  345.    return new_segment;
  346. }
  347.  
  348.  
  349. PathSegment *
  350. path_prepend_segment  (Path * cur_path,
  351.                PathCurve * cur_curve,
  352.                SegmentType type,
  353.                gint x,
  354.                gint y)
  355. {
  356.    PathSegment * tmp = cur_curve->segments;
  357.    PathSegment * new_segment = NULL;
  358.    
  359. #ifdef PATH_TOOL_DEBUG
  360.       fprintf(stderr, "path_prepend_segment\n");
  361. #endif PATH_TOOL_DEBUG
  362.  
  363.    if (cur_curve) {
  364.       tmp = cur_curve->segments;
  365.    
  366.       if (tmp == NULL || tmp->prev == NULL) {
  367.          new_segment = g_new (PathSegment, 1);
  368.          
  369.          new_segment->type = type;
  370.          new_segment->x = x;
  371.          new_segment->y = y;
  372.          new_segment->flags = 0;
  373.          new_segment->parent = cur_curve;
  374.          new_segment->next = tmp;
  375.          new_segment->prev = NULL;
  376.          new_segment->data = NULL;
  377.          
  378.          if (tmp) 
  379.             tmp->prev = new_segment;
  380.  
  381.          cur_curve->segments = new_segment;
  382.          cur_curve->cur_segment = new_segment;
  383.  
  384.      path_curve_init_segment (new_segment);
  385.       }
  386. #ifdef PATH_TOOL_DEBUG
  387.       else
  388.          fprintf(stderr, "Fatal Error: path_prepend_segment called with a closed curve\n");
  389. #endif PATH_TOOL_DEBUG
  390.    }
  391. #ifdef PATH_TOOL_DEBUG
  392.    else
  393.       fprintf(stderr, "Fatal Error: path_prepend_segment called without valid curve\n");
  394. #endif PATH_TOOL_DEBUG
  395.    
  396.    return new_segment;
  397. }
  398.  
  399. PathSegment *
  400. path_split_segment   (PathSegment *segment,
  401.               gdouble position)
  402. {
  403.    PathSegment * new_segment = NULL;
  404.  
  405. #ifdef PATH_TOOL_DEBUG
  406.    fprintf(stderr, "path_split_segment\n");
  407. #endif PATH_TOOL_DEBUG
  408.    if (segment && segment->next) {
  409.       new_segment = g_new (PathSegment, 1);
  410.  
  411.       new_segment->type = segment->type;
  412.       /* XXX: Giving PathTool as NULL Pointer! */
  413.       path_curve_get_point (NULL, segment, position, &(new_segment->x), &(new_segment->y));
  414.       new_segment->flags = 0;
  415.       new_segment->parent = segment->parent;
  416.       new_segment->next = segment->next;
  417.       new_segment->prev = segment;
  418.       new_segment->data = NULL;
  419.  
  420.       path_curve_init_segment (new_segment);
  421.  
  422.       new_segment->next->prev = new_segment;
  423.       segment->next = new_segment;
  424.       
  425.       return new_segment;
  426.  
  427.    }
  428. #ifdef PATH_TOOL_DEBUG
  429.    else 
  430.       fprintf(stderr, "path_split_segment without valid segment\n");
  431. #endif PATH_TOOL_DEBUG
  432.    return NULL;
  433.  
  434. }
  435.  
  436. /*
  437.  * Join two arbitrary endpoints and free the parent from the second
  438.  * segment, if it differs from the first parents.
  439.  */
  440.  
  441. void
  442. path_join_curves (PathSegment *segment1,
  443.           PathSegment *segment2)
  444. {
  445.    PathCurve *curve1, *curve2;
  446.    PathSegment *tmp;
  447.  
  448.    if ((segment1->next && segment1->prev) || (segment2->next && segment2->prev)) {
  449. #ifdef PATH_TOOL_DEBUG
  450.       fprintf(stderr, "Fatal Error: path_join_curves called with a closed segment\n");
  451. #endif PATH_TOOL_DEBUG
  452.       return;
  453.    }
  454.    if (segment1->parent == segment2->parent) {
  455. #ifdef PATH_TOOL_DEBUG
  456.       fprintf (stderr, "Joining beginning and end of the same curve...\n");
  457. #endif PATH_TOOL_DEBUG
  458.       if (segment2->next == NULL) {
  459.      segment2->next = segment1;
  460.      segment1->prev = segment2;
  461.       } else {
  462.      segment2->prev = segment1;
  463.      segment1->next = segment2;
  464.       }
  465. /* XXX: Probably some segment-updates needed */
  466.       return;
  467.    }
  468.  
  469.    if (segment1->next == NULL && segment2->next == NULL) {
  470. #ifdef PATH_TOOL_DEBUG
  471.       fprintf (stderr, "Flipping second curve (next, next)...\n");
  472. #endif PATH_TOOL_DEBUG
  473.       path_flip_curve (segment2->parent);
  474.       /* segment2 = segment2->parent->segments;
  475.        */
  476.    }
  477.       
  478.    if (segment1->prev == NULL && segment2->prev == NULL) {
  479. #ifdef PATH_TOOL_DEBUG
  480.       fprintf (stderr, "Flipping second curve (prev, prev)...\n");
  481. #endif PATH_TOOL_DEBUG
  482.       path_flip_curve (segment2->parent);
  483.       /* segment2 = segment2->parent->segments;
  484.        * while (segment2->next)
  485.        * segment2 = segment2->next;
  486.        */
  487.    }
  488.       
  489.    if (segment1->next == NULL && segment2->prev == NULL) {
  490. #ifdef PATH_TOOL_DEBUG
  491.       fprintf (stderr, "Appending second to first curve...\n");
  492. #endif PATH_TOOL_DEBUG
  493.       curve1 = segment1->parent;
  494.       curve2 = segment2->parent;
  495.       
  496.       segment1->next = segment2;
  497.       segment2->prev = segment1;
  498.       
  499.       curve2->segments = NULL;
  500.       
  501.       if (curve2->prev)
  502.      curve2->prev->next = curve2->next;
  503.       if (curve2->next)
  504.      curve2->next->prev = curve2->prev;
  505.       
  506.       if (curve2->parent->curves == curve2)
  507.      curve2->parent->curves = curve2->next;
  508.       
  509.       path_free_curve (curve2);
  510.       
  511.       tmp = segment2;
  512.       
  513.       while (tmp) {
  514.      tmp->parent = curve1;
  515.      tmp = tmp->next;
  516.       }
  517. /* XXX: Probably some segment-updates needed */
  518.       return;
  519.    }
  520.  
  521.    if (segment1->prev == NULL && segment2->next == NULL) {
  522. #ifdef PATH_TOOL_DEBUG
  523.       fprintf (stderr, "Prepending second to first curve...\n");
  524. #endif PATH_TOOL_DEBUG
  525.       curve1 = segment1->parent;
  526.       curve2 = segment2->parent;
  527.       
  528.       segment1->prev = segment2;
  529.       segment2->next = segment1;
  530.       
  531.       curve2->segments = NULL;
  532.       if (curve2->prev)
  533.      curve2->prev->next = curve2->next;
  534.       if (curve2->next)
  535.      curve2->next->prev = curve2->prev;
  536.       if (curve2->parent->curves == curve2)
  537.      curve2->parent->curves = curve2->next;
  538.       path_free_curve (curve2);
  539.       
  540.       tmp = segment2;
  541.       
  542.       while (tmp) {
  543.      tmp->parent = curve1;
  544.      curve1->segments = tmp;
  545.      tmp = tmp->prev;
  546.       }
  547.       return;
  548. /* XXX: Probably some segment-updates needed */
  549.    }
  550.  
  551. #ifdef PATH_TOOL_DEBUG
  552.    fprintf (stderr, "Cant join these curves yet...\nThis should not happen.");
  553.    return;
  554. #endif PATH_TOOL_DEBUG
  555.  
  556. }
  557.  
  558. /*
  559.  * This function reverses the order of the anchors. This is
  560.  * necessary for some joining operations.
  561.  */
  562. void
  563. path_flip_curve (PathCurve *curve)
  564. {
  565.    gpointer *end_data;
  566.    SegmentType end_type;
  567.  
  568.    PathSegment *tmp, *tmp2;
  569.    
  570.    if (!curve && !curve->segments) {
  571. #ifdef PATH_TOOL_DEBUG
  572.       fprintf (stderr, "path_flip_curve: No curve o no segments to flip!\n");
  573. #endif PATH_TOOL_DEBUG
  574.       return;
  575.    }
  576.    
  577.    tmp = curve->segments;
  578.  
  579.    while (tmp->next)
  580.       tmp = tmp->next;
  581.    
  582.    end_data = tmp->data;
  583.    end_type = tmp->type;
  584.  
  585.    tmp->parent->segments = tmp;
  586.    
  587.    while (tmp) {
  588.       tmp2 = tmp->next;
  589.       tmp->next = tmp->prev;
  590.       tmp->prev = tmp2;
  591.       if (tmp->next) {
  592.      tmp->type = tmp->next->type;
  593.      tmp->data = tmp->next->data;
  594.       } else {
  595.      tmp->type = end_type;
  596.      tmp->data = end_data;
  597.       }
  598.       path_curve_flip_segment (tmp);
  599.       tmp = tmp->next;
  600.    }
  601. }
  602.  
  603.  
  604. void
  605. path_free_path (Path * path)
  606. {
  607.    PathCurve *tmp1, *tmp2;
  608.    
  609.    if (path)
  610.    {
  611.       tmp2 = path->curves;
  612.  
  613.       while ((tmp1 = tmp2) != NULL)
  614.       {
  615.          tmp2 = tmp1->next;
  616.      path_free_curve (tmp1);
  617.       } 
  618.       g_string_free(path->name, TRUE);
  619.       g_free(path);
  620.    }
  621. }
  622.  
  623. void
  624. path_free_curve (PathCurve *curve)
  625. {
  626.    PathSegment *tmp1, *tmp2;
  627.    
  628.    if (curve)
  629.    {
  630.       tmp2 = curve->segments;
  631.  
  632.       /* break closed curves */
  633.       if (tmp2 && tmp2->prev)
  634.      tmp2->prev->next = NULL;
  635.  
  636.       while ((tmp1 = tmp2) != NULL)
  637.       {
  638.          tmp2 = tmp1->next;
  639.      path_free_segment (tmp1);
  640.       } 
  641.       g_free(curve);
  642.    }
  643. }
  644.  
  645. void
  646. path_free_segment (PathSegment *segment)
  647. {
  648.    if (segment)
  649.    {
  650.       /* Clear the active flag to keep path_tool->single_active_segment
  651.        * consistent */
  652.       
  653.  
  654.       path_set_flags (segment->parent->parent->path_tool, segment->parent->parent,
  655.                   segment->parent, segment, 0, SEGMENT_ACTIVE);
  656.  
  657.       path_curve_cleanup_segment(segment);
  658.  
  659.       g_free (segment);
  660.    }
  661. }
  662.  
  663. void
  664. path_delete_curve (PathCurve *curve)
  665. {
  666.    if (curve)
  667.    {
  668.       if (curve->next)
  669.      curve->next->prev = curve->prev;
  670.       if (curve->prev)
  671.      curve->prev->next = curve->next;
  672.       
  673.       if (curve == curve->parent->curves) {
  674.      curve->parent->curves = curve->next;
  675.       }
  676.       
  677.       path_free_curve (curve);
  678.    }
  679. }
  680.  
  681. void
  682. path_delete_segment (PathSegment *segment)
  683. {
  684.    if (segment)
  685.    {
  686.       if (segment->next)
  687.      segment->next->prev = segment->prev;
  688.       if (segment->prev)
  689.      segment->prev->next = segment->next;
  690.       
  691.       /* If the remaining curve is closed and has a
  692.        * single point only, open it.
  693.        */
  694.       if (segment->next == segment->prev && segment->next)
  695.      segment->next->next = segment->next->prev = NULL;
  696.  
  697.       if (segment == segment->parent->segments)
  698.      segment->parent->segments = segment->next;
  699.  
  700.       if (segment->parent->segments == NULL)
  701.         path_delete_curve (segment->parent);
  702.       
  703.       path_free_segment (segment);
  704.  
  705.       /*
  706.        * here we have to update the surrounding segments
  707.        */
  708. /* XXX: Please add path_curve_update_segment here */
  709.    }
  710. }
  711.  
  712.  
  713. /*
  714.  * A function to determine, which object is hit by the cursor
  715.  */
  716.  
  717. gint
  718. path_tool_cursor_position (Tool *tool,
  719.                gint x,
  720.                gint y,
  721.                gint halfwidth,
  722.                Path **pathP,
  723.                PathCurve **curveP,
  724.                PathSegment **segmentP,
  725.                gdouble *positionP,
  726.                gint *handle_idP)
  727. {
  728.    gdouble pos;
  729.    gint handle_id;
  730.  
  731.    if (path_tool_on_anchors (tool, x, y, halfwidth, pathP, curveP, segmentP))
  732.       return ON_ANCHOR;
  733.  
  734.    handle_id = path_tool_on_handles (tool, x, y, halfwidth, pathP, curveP, segmentP);
  735.    if (handle_id) {
  736.       if (handle_idP) (*handle_idP) = handle_id;
  737.       return ON_HANDLE;
  738.    }
  739.  
  740.    pos = path_tool_on_curve (tool, x, y, halfwidth, pathP, curveP, segmentP);
  741.    if (pos >= 0 && pos <= 1) {
  742.       if (positionP) (*positionP) = pos;
  743.       return ON_CURVE;
  744.    }
  745.  
  746.  
  747.    return ON_CANVAS;
  748. }
  749.       
  750.      
  751. /**************************************************************
  752.  * The click-callbacks for the tool
  753.  */
  754.  
  755. void
  756. path_tool_button_press (Tool           *tool,
  757.             GdkEventButton *bevent,
  758.             gpointer        gdisp_ptr)
  759. {
  760.    GDisplay * gdisp;
  761.    PathTool * path_tool;
  762.    gint grab_pointer=0;
  763.    gint x, y, halfwidth, dummy;
  764.  
  765. #ifdef PATH_TOOL_DEBUG
  766.    fprintf (stderr, "path_tool_button_press\n");
  767. #endif PATH_TOOL_DEBUG
  768.  
  769.    gdisp = (GDisplay *) gdisp_ptr;
  770.    path_tool = (PathTool *) tool->private;
  771.    tool->gdisp_ptr = gdisp_ptr;
  772.   
  773.    /* Transform window-coordinates to canvas-coordinates */
  774.    gdisplay_untransform_coords (gdisp, bevent->x, bevent->y, &x, &y, TRUE, 0);
  775. #ifdef PATH_TOOL_DEBUG
  776.    fprintf(stderr, "Clickcoordinates %d, %d\n",x,y);
  777. #endif PATH_TOOL_DEBUG
  778.    path_tool->click_x = x;
  779.    path_tool->click_y = y;
  780.    path_tool->click_modifier = bevent->state;
  781.    /* get halfwidth in image coord */
  782.    gdisplay_untransform_coords (gdisp, bevent->x + PATH_TOOL_HALFWIDTH, 0, &halfwidth, &dummy, TRUE, 0);
  783.    halfwidth -= x;
  784.    path_tool->click_halfwidth = halfwidth;
  785.    
  786.    if (!path_tool->cur_path->curves)
  787.       draw_core_start (path_tool->core, gdisp->canvas->window, tool);
  788.  
  789.    /* determine point, where clicked,
  790.     * switch accordingly.
  791.     */
  792.   
  793.    path_tool->click_type = path_tool_cursor_position (tool, x, y, halfwidth,
  794.                                                      &(path_tool->click_path),
  795.                              &(path_tool->click_curve),
  796.                              &(path_tool->click_segment),
  797.                              &(path_tool->click_position),
  798.                              &(path_tool->click_handle_id));
  799.   
  800.    switch (path_tool->click_type)
  801.    {
  802.    case ON_CANVAS:
  803.       grab_pointer = path_tool_button_press_canvas(tool, bevent, gdisp);
  804.       break;
  805.  
  806.    case ON_ANCHOR:
  807.       grab_pointer = path_tool_button_press_anchor(tool, bevent, gdisp);
  808.       break;
  809.  
  810.    case ON_HANDLE:
  811.       grab_pointer = path_tool_button_press_handle(tool, bevent, gdisp);
  812.       break;
  813.  
  814.    case ON_CURVE:
  815.       grab_pointer = path_tool_button_press_curve(tool, bevent, gdisp);
  816.       break;
  817.  
  818.    default:
  819.       g_message("Huh? Whats happening here? (button_press_*)");
  820.    }
  821.   
  822.    if (grab_pointer)
  823.       gdk_pointer_grab (gdisp->canvas->window, FALSE,
  824.                 GDK_POINTER_MOTION_HINT_MASK |
  825.             GDK_BUTTON1_MOTION_MASK |
  826.             GDK_BUTTON_RELEASE_MASK,
  827.             NULL, NULL, bevent->time);
  828.  
  829.    tool->state = ACTIVE;
  830.  
  831. }
  832.  
  833. gint
  834. path_tool_button_press_anchor (Tool *tool,
  835.                                GdkEventButton *bevent,
  836.                                GDisplay *gdisp)
  837. {
  838.    static guint32 last_click_time=0;
  839.    gboolean doubleclick=FALSE;
  840.    PathTool *path_tool = tool->private;
  841.    
  842.    Path * cur_path = path_tool->cur_path;
  843.    PathSegment *p_sas;
  844.    gint grab_pointer;
  845.    
  846. #ifdef PATH_TOOL_DEBUG
  847.    fprintf(stderr, "path_tool_button_press_anchor:\n");
  848. #endif PATH_TOOL_DEBUG
  849.    
  850.    grab_pointer = 1;
  851.  
  852.    if (!cur_path) {
  853. #ifdef PATH_TOOL_DEBUG
  854.       fprintf (stderr, "Fatal error: No current Path\n");
  855. #endif PATH_TOOL_DEBUG
  856.       return 0;
  857.    }
  858.    
  859.    /* 
  860.     * We have to determine, if this was a doubleclick for ourself, because
  861.     * disp_callback.c ignores the GDK_[23]BUTTON_EVENT's and adding them to
  862.     * the switch statement confuses some tools.
  863.     */
  864.    if (bevent->time - last_click_time < 250) {
  865.       doubleclick=TRUE;
  866. #ifdef PATH_TOOL_DEBUG
  867.       fprintf (stderr, "Doppelclick!\n");
  868. #endif PATH_TOOL_DEBUG
  869.    } else
  870.       doubleclick=FALSE;
  871.    last_click_time = bevent->time;
  872.  
  873.  
  874.    draw_core_pause (path_tool->core, tool);
  875.   
  876.    /* The user pressed on an anchor:
  877.     *  normally this activates this anchor
  878.     *  + SHIFT toggles the activity of an anchor.
  879.     *  if this anchor is at the end of an open curve and the other
  880.     *  end is active, close the curve.
  881.     *  
  882.     *  Doubleclick (de)activates the whole curve (not Path!).
  883.     */
  884.  
  885.    p_sas = path_tool->single_active_segment;
  886.  
  887. #ifdef PATH_TOOL_DEBUG
  888.    fprintf (stderr, "p_sas: %p\n", p_sas);
  889. #endif PATH_TOOL_DEBUG
  890.  
  891.    if (path_tool->click_modifier & GDK_SHIFT_MASK) {
  892.       if (path_tool->active_count == 1 && p_sas && p_sas != path_tool->click_segment &&
  893.           (p_sas->next == NULL || p_sas->prev == NULL) &&
  894.       (path_tool->click_segment->next == NULL || path_tool->click_segment->prev == NULL)) {
  895.      /*
  896.       * if this is the end of an open curve and the single active segment was another
  897.       * open end, connect those ends.
  898.       */
  899.      path_join_curves (path_tool->click_segment, p_sas);
  900.      path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
  901.                      NULL, 0, SEGMENT_ACTIVE);
  902.       }
  903.  
  904.       if (doubleclick)
  905.      /*
  906.       * Doubleclick set the whole curve to the same state, depending on the
  907.       * state of the clicked anchor.
  908.       */
  909.      if (path_tool->click_segment->flags & SEGMENT_ACTIVE)
  910.         path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
  911.                     NULL, SEGMENT_ACTIVE, 0);
  912.      else
  913.         path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
  914.                          NULL, 0, SEGMENT_ACTIVE);
  915.       else
  916.      /*
  917.       * Toggle the state of the clicked anchor.
  918.       */
  919.      if (path_tool->click_segment->flags & SEGMENT_ACTIVE)
  920.         path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
  921.                      path_tool->click_segment, 0, SEGMENT_ACTIVE);
  922.      else
  923.         path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
  924.                     path_tool->click_segment, SEGMENT_ACTIVE, 0);
  925.    }
  926.    /*
  927.     * Delete anchors, when CONTROL is pressed
  928.     */
  929.    else if (path_tool->click_modifier & GDK_CONTROL_MASK)
  930.    {
  931.       if (path_tool->click_segment->flags & SEGMENT_ACTIVE)
  932.       {
  933.      if (path_tool->click_segment->prev)
  934.         path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
  935.                        path_tool->click_segment->prev, SEGMENT_ACTIVE, 0);
  936.           else if (path_tool->click_segment->next)
  937.            path_set_flags (path_tool, path_tool->click_path, path_tool->click_curve,
  938.                     path_tool->click_segment->next, SEGMENT_ACTIVE, 0);
  939.       }
  940.  
  941.       path_delete_segment (path_tool->click_segment);
  942.       path_tool->click_segment = NULL;
  943.       /* Maybe CTRL-ALT Click should remove the whole curve? Or the active points? */
  944.    }
  945.    else if (!(path_tool->click_segment->flags & SEGMENT_ACTIVE))
  946.    {
  947.       path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
  948.       path_set_flags (path_tool, cur_path, path_tool->click_curve, path_tool->click_segment, SEGMENT_ACTIVE, 0);
  949.    }
  950.    
  951.  
  952.    draw_core_resume(path_tool->core, tool);
  953.  
  954.    return grab_pointer;
  955. }
  956.  
  957.  
  958. gint
  959. path_tool_button_press_handle (Tool *tool,
  960.                                GdkEventButton *bevent,
  961.                                GDisplay *gdisp)
  962. {
  963.    static guint32 last_click_time=0;
  964.    gboolean doubleclick=FALSE;
  965.    PathTool *path_tool = tool->private;
  966.    
  967.    Path * cur_path = path_tool->cur_path;
  968.    gint grab_pointer;
  969.    
  970. #ifdef PATH_TOOL_DEBUG
  971.    fprintf(stderr, "path_tool_button_press_handle:\n");
  972. #endif PATH_TOOL_DEBUG
  973.    
  974.    grab_pointer = 1;
  975.  
  976.    if (!cur_path) {
  977. #ifdef PATH_TOOL_DEBUG
  978.       fprintf (stderr, "Fatal error: No current Path\n");
  979. #endif PATH_TOOL_DEBUG
  980.       return 0;
  981.    }
  982.    
  983.    /* 
  984.     * We have to determine, if this was a doubleclick for ourself, because
  985.     * disp_callback.c ignores the GDK_[23]BUTTON_EVENT's and adding them to
  986.     * the switch statement confuses some tools.
  987.     */
  988.    if (bevent->time - last_click_time < 250) {
  989.       doubleclick=TRUE;
  990. #ifdef PATH_TOOL_DEBUG
  991.       fprintf (stderr, "Doppelclick!\n");
  992. #endif PATH_TOOL_DEBUG
  993.    } else
  994.       doubleclick=FALSE;
  995.    last_click_time = bevent->time;
  996.  
  997.    return grab_pointer;
  998. }
  999.  
  1000. gint
  1001. path_tool_button_press_canvas (Tool *tool,
  1002.                                GdkEventButton *bevent,
  1003.                                GDisplay *gdisp)
  1004. {
  1005.    PathTool *path_tool = tool->private;
  1006.    
  1007.    Path * cur_path = path_tool->cur_path;
  1008.    PathCurve * cur_curve;
  1009.    PathSegment * cur_segment;
  1010.    gint grab_pointer;
  1011.    
  1012. #ifdef PATH_TOOL_DEBUG
  1013.    fprintf(stderr, "path_tool_button_press_canvas:\n");
  1014. #endif PATH_TOOL_DEBUG
  1015.    
  1016.    grab_pointer = 1;
  1017.    
  1018.    if (!cur_path) {
  1019. #ifdef PATH_TOOL_DEBUG
  1020.       fprintf (stderr, "Fatal error: No current Path\n");
  1021. #endif PATH_TOOL_DEBUG
  1022.       return 0;
  1023.    }
  1024.    
  1025.    draw_core_pause (path_tool->core, tool);
  1026.    
  1027.    if (path_tool->active_count == 1 && path_tool->single_active_segment != NULL
  1028.        && (path_tool->single_active_segment->prev == NULL || path_tool->single_active_segment->next == NULL)) {
  1029.       cur_segment = path_tool->single_active_segment;
  1030.       cur_curve = cur_segment->parent;
  1031.  
  1032.       path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
  1033.  
  1034.       if (cur_segment->next == NULL)
  1035.      cur_curve->cur_segment = path_append_segment(cur_path, cur_curve, SEGMENT_BEZIER, path_tool->click_x, path_tool->click_y);
  1036.       else
  1037.      cur_curve->cur_segment = path_prepend_segment(cur_path, cur_curve, SEGMENT_BEZIER, path_tool->click_x, path_tool->click_y);
  1038.       if (cur_curve->cur_segment) {
  1039.      path_set_flags (path_tool, cur_path, cur_curve, cur_curve->cur_segment, SEGMENT_ACTIVE, 0);
  1040.       }
  1041.    } else {
  1042.       if (path_tool->active_count == 0) {
  1043.      path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
  1044.      cur_path->cur_curve = path_add_curve(cur_path, path_tool->click_x, path_tool->click_y);
  1045.      path_set_flags (path_tool, cur_path, cur_path->cur_curve, cur_path->cur_curve->segments, SEGMENT_ACTIVE, 0);
  1046.       } else {
  1047.      path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
  1048.       }
  1049.    }
  1050.    
  1051.    draw_core_resume(path_tool->core, tool);
  1052.  
  1053.    return 0;
  1054. }
  1055.  
  1056. gint
  1057. path_tool_button_press_curve (Tool *tool,
  1058.                   GdkEventButton *bevent,
  1059.                   GDisplay *gdisp)
  1060. {
  1061.    PathTool *path_tool = tool->private;
  1062.    
  1063.    Path * cur_path = path_tool->cur_path;
  1064.    PathSegment * cur_segment;
  1065.    gint grab_pointer;
  1066.    
  1067. #ifdef PATH_TOOL_DEBUG
  1068.    fprintf(stderr, "path_tool_button_press_curve:\n");
  1069. #endif PATH_TOOL_DEBUG
  1070.    
  1071.    grab_pointer = 1;
  1072.    
  1073.    if (!cur_path) {
  1074. #ifdef PATH_TOOL_DEBUG
  1075.       fprintf (stderr, "Fatal error: No current Path\n");
  1076. #endif PATH_TOOL_DEBUG
  1077.       return 0;
  1078.    }
  1079.    
  1080.    draw_core_pause (path_tool->core, tool);
  1081.    
  1082.    if (path_tool->click_modifier & GDK_SHIFT_MASK) {
  1083.       cur_segment = path_curve_insert_anchor (path_tool, path_tool->click_segment, path_tool->click_position);
  1084.       path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
  1085.       path_set_flags (path_tool, cur_path, path_tool->click_curve, cur_segment, SEGMENT_ACTIVE, 0);
  1086.       path_tool->click_type = ON_ANCHOR;
  1087.       path_tool->click_segment = cur_segment;
  1088.  
  1089.    } else {
  1090.       path_set_flags (path_tool, cur_path, NULL, NULL, 0, SEGMENT_ACTIVE);
  1091.       path_set_flags (path_tool, cur_path, path_tool->click_curve, path_tool->click_segment, SEGMENT_ACTIVE, 0);
  1092.       path_set_flags (path_tool, cur_path, path_tool->click_curve, path_tool->click_segment->next, SEGMENT_ACTIVE, 0);
  1093.    }
  1094.    draw_core_resume(path_tool->core, tool);
  1095.  
  1096.    return 0;
  1097. }
  1098.  
  1099. void
  1100. path_tool_button_release (Tool           *tool,
  1101.               GdkEventButton *bevent,
  1102.               gpointer        gdisp_ptr)
  1103. {
  1104.    GDisplay * gdisp;
  1105.    PathTool * path_tool;
  1106.  
  1107. #ifdef PATH_TOOL_DEBUG
  1108.    fprintf (stderr, "path_tool_button_release\n");
  1109. #endif PATH_TOOL_DEBUG
  1110.  
  1111.    gdisp = (GDisplay *) gdisp_ptr;
  1112.    path_tool = (PathTool *) tool->private;
  1113.    
  1114.    path_tool->state &= ~PATH_TOOL_DRAG;
  1115.  
  1116.    gdk_pointer_ungrab (bevent->time);
  1117.    gdk_flush ();
  1118. }
  1119.  
  1120.  
  1121. /**************************************************************
  1122.  * The motion-callbacks for the tool
  1123.  */
  1124.  
  1125. void
  1126. path_tool_motion (Tool           *tool,
  1127.           GdkEventMotion *mevent,
  1128.           gpointer        gdisp_ptr)
  1129. {
  1130.    GDisplay * gdisp;
  1131.    PathTool * path_tool;
  1132.  
  1133.    if (gtk_events_pending()) return;
  1134.    
  1135.    gdisp = (GDisplay *) gdisp_ptr;
  1136.    path_tool = (PathTool *) tool->private;
  1137.  
  1138.    switch (path_tool->click_type) {
  1139.    case ON_ANCHOR:
  1140.       path_tool_motion_anchor (tool, mevent, gdisp);
  1141.       break;
  1142.    case ON_HANDLE:
  1143.       path_tool_motion_handle (tool, mevent, gdisp);
  1144.       break;
  1145.    case ON_CURVE:
  1146.       path_tool_motion_curve (tool, mevent, gdisp);
  1147.       break;
  1148.    default:
  1149.       return;
  1150.    }
  1151.  
  1152. }
  1153.  
  1154. void
  1155. path_tool_motion_anchor (Tool           *tool,
  1156.                  GdkEventMotion *mevent,
  1157.                  GDisplay       *gdisp)
  1158. {
  1159.    PathTool * path_tool;
  1160.    gdouble dx, dy, d;
  1161.    gint x,y;
  1162.    static gint dxsum = 0;
  1163.    static gint dysum = 0;
  1164.    
  1165.    path_tool = (PathTool *) tool->private;
  1166.    
  1167.    /*
  1168.     * Dont do anything, if the user clicked with pressed CONTROL-Key,
  1169.     * because he deleted an anchor.
  1170.     */
  1171.    if (path_tool->click_modifier & GDK_CONTROL_MASK)
  1172.       return;
  1173.    
  1174.    if (!(path_tool->state & PATH_TOOL_DRAG))
  1175.    {
  1176.       path_tool->state |= PATH_TOOL_DRAG;
  1177.       dxsum = 0;
  1178.       dysum = 0;
  1179.    }
  1180.  
  1181.    gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, TRUE, 0);
  1182.    
  1183.    dx = x - path_tool->click_x - dxsum;
  1184.    dy = y - path_tool->click_y - dysum;
  1185.    
  1186.    /* restrict to horizontal/vertical lines, if modifiers are pressed
  1187.     * I'm not sure, if this is intuitive for the user. Esp. When moving
  1188.     * an endpoint of an curve I'd expect, that the *line* is
  1189.     * horiz/vertical - not the delta to the point, where the point was
  1190.     * originally...
  1191.     */
  1192.    if (mevent->state & GDK_MOD1_MASK)
  1193.    {
  1194.       if (mevent->state & GDK_CONTROL_MASK)
  1195.       {
  1196.      d  = (fabs(dx) + fabs(dy)) / 2;  
  1197.      d  = (fabs(x - path_tool->click_x) + fabs(y - path_tool->click_y)) / 2;  
  1198.      
  1199.      dx = ((x < path_tool->click_x) ? -d : d ) - dxsum;
  1200.      dy = ((y < path_tool->click_y) ? -d : d ) - dysum;
  1201.       }
  1202.       else
  1203.      dx = - dxsum;
  1204.    }
  1205.    else if (mevent->state & GDK_CONTROL_MASK)
  1206.       dy = - dysum;
  1207.    
  1208.  
  1209.    path_tool->draw |= PATH_TOOL_REDRAW_ACTIVE;
  1210.    
  1211.    draw_core_pause(path_tool->core, tool);
  1212.  
  1213.    path_offset_active (path_tool->cur_path, dx, dy);
  1214.  
  1215.    dxsum += dx;
  1216.    dysum += dy;
  1217.  
  1218.    draw_core_resume (path_tool->core, tool);
  1219.    
  1220.    path_tool->draw &= ~PATH_TOOL_REDRAW_ACTIVE;
  1221.  
  1222. }
  1223.  
  1224. void
  1225. path_tool_motion_handle (Tool           *tool,
  1226.                  GdkEventMotion *mevent,
  1227.                  GDisplay       *gdisp)
  1228. {
  1229.    PathTool * path_tool;
  1230.    gdouble dx, dy;
  1231.    gint x,y;
  1232.    static gint dxsum = 0;
  1233.    static gint dysum = 0;
  1234.    
  1235.    path_tool = (PathTool *) tool->private;
  1236.    
  1237.    /*
  1238.     * Dont do anything, if the user clicked with pressed CONTROL-Key,
  1239.     * because he moved the handle to the anchor an anchor. 
  1240.     * XXX: Not yet! :-)
  1241.     */
  1242.    if (path_tool->click_modifier & GDK_CONTROL_MASK)
  1243.       return;
  1244.    
  1245.    if (!(path_tool->state & PATH_TOOL_DRAG))
  1246.    {
  1247.       path_tool->state |= PATH_TOOL_DRAG;
  1248.       dxsum = 0;
  1249.       dysum = 0;
  1250.    }
  1251.  
  1252.    gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, TRUE, 0);
  1253.    
  1254.    dx = x - path_tool->click_x - dxsum;
  1255.    dy = y - path_tool->click_y - dysum;
  1256.    
  1257.    path_tool->draw |= PATH_TOOL_REDRAW_ACTIVE;
  1258.    
  1259.    draw_core_pause(path_tool->core, tool);
  1260.  
  1261.    path_curve_drag_handle (path_tool, path_tool->click_segment, dx, dy, path_tool->click_handle_id);
  1262.  
  1263.    dxsum += dx;
  1264.    dysum += dy;
  1265.  
  1266.    draw_core_resume (path_tool->core, tool);
  1267.    
  1268.    path_tool->draw &= ~PATH_TOOL_REDRAW_ACTIVE;
  1269.  
  1270. }
  1271.    
  1272.  
  1273. void
  1274. path_tool_motion_curve (Tool           *tool,
  1275.                 GdkEventMotion *mevent,
  1276.                 GDisplay       *gdisp)
  1277. {
  1278.    PathTool * path_tool;
  1279.    gdouble dx, dy;
  1280.    gint x,y;
  1281.    static gint dxsum = 0;
  1282.    static gint dysum = 0;
  1283.    
  1284.    path_tool = (PathTool *) tool->private;
  1285.    
  1286.    if (!(path_tool->state & PATH_TOOL_DRAG))
  1287.    {
  1288.       path_tool->state |= PATH_TOOL_DRAG;
  1289.       dxsum = 0;
  1290.       dysum = 0;
  1291.    }
  1292.  
  1293.    gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, TRUE, 0);
  1294.    
  1295.    dx = x - path_tool->click_x - dxsum;
  1296.    dy = y - path_tool->click_y - dysum;
  1297.    
  1298.    path_tool->draw |= PATH_TOOL_REDRAW_ACTIVE;
  1299.    
  1300.    draw_core_pause(path_tool->core, tool);
  1301.  
  1302.    path_curve_drag_segment (path_tool, path_tool->click_segment, path_tool->click_position, dx, dy);
  1303.  
  1304.    dxsum += dx;
  1305.    dysum += dy;
  1306.  
  1307.    draw_core_resume (path_tool->core, tool);
  1308.    
  1309.    path_tool->draw &= ~PATH_TOOL_REDRAW_ACTIVE;
  1310.  
  1311. }
  1312.    
  1313.  
  1314. void
  1315. path_tool_cursor_update (Tool           *tool,
  1316.              GdkEventMotion *mevent,
  1317.              gpointer        gdisp_ptr)
  1318. {
  1319.    PathTool *path_tool;
  1320.    GDisplay *gdisp;
  1321.    gint     x, y, halfwidth, dummy, cursor_location;
  1322.   
  1323. #ifdef PATH_TOOL_DEBUG
  1324.    /* fprintf (stderr, "path_tool_cursor_update\n");
  1325.     */
  1326. #endif PATH_TOOL_DEBUG
  1327.  
  1328.    gdisp = (GDisplay *) gdisp_ptr;
  1329.    path_tool = (PathTool *) tool->private;
  1330.  
  1331.    gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, TRUE, 0);
  1332.    /* get halfwidth in image coord */
  1333.    gdisplay_untransform_coords (gdisp, mevent->x + PATH_TOOL_HALFWIDTH, 0, &halfwidth, &dummy, TRUE, 0);
  1334.    halfwidth -= x;
  1335.  
  1336.    cursor_location = path_tool_cursor_position (tool, x, y, halfwidth, NULL, NULL, NULL, NULL, NULL);
  1337.  
  1338.    switch (cursor_location) {
  1339.    case ON_CANVAS:
  1340.       gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE1AP_CURSOR);
  1341.       break;
  1342.    case ON_ANCHOR:
  1343.       gdisplay_install_tool_cursor (gdisp, GDK_FLEUR);
  1344.       break;
  1345.    case ON_HANDLE:
  1346.       gdisplay_install_tool_cursor (gdisp, GDK_CROSSHAIR);
  1347.       break;
  1348.    case ON_CURVE:
  1349.       gdisplay_install_tool_cursor (gdisp, GDK_CROSSHAIR);
  1350.       break;
  1351.    default:
  1352.       gdisplay_install_tool_cursor (gdisp, GDK_QUESTION_ARROW);
  1353.       break;
  1354.    }
  1355. }
  1356.  
  1357. /**************************************************************
  1358.  * Tool-control functions
  1359.  */
  1360.  
  1361. void
  1362. path_tool_control (Tool       *tool,
  1363.            ToolAction  action,
  1364.            gpointer    gdisp_ptr)
  1365. {
  1366.    GDisplay * gdisp;
  1367.    PathTool * path_tool;
  1368.  
  1369. #ifdef PATH_TOOL_DEBUG
  1370.    fprintf (stderr, "path_tool_control\n");
  1371. #endif PATH_TOOL_DEBUG
  1372.  
  1373.    gdisp = (GDisplay *) tool->gdisp_ptr;
  1374.    path_tool = (PathTool *) tool->private;
  1375.  
  1376.    switch (action)
  1377.      {
  1378.      case PAUSE:
  1379.         draw_core_pause (path_tool->core, tool);
  1380.         break;
  1381.  
  1382.      case RESUME:
  1383.         draw_core_resume (path_tool->core, tool);
  1384.         break;
  1385.  
  1386.      case HALT:
  1387. #ifdef PATH_TOOL_DEBUG
  1388.         fprintf (stderr, "path_tool_control: HALT\n");
  1389. #endif PATH_TOOL_DEBUG
  1390.         draw_core_stop (path_tool->core, tool);
  1391.         tool->state = INACTIVE;
  1392.         break;
  1393.  
  1394.      default:
  1395.         break;
  1396.      }
  1397. #ifdef PATH_TOOL_DEBUG
  1398.      fprintf (stderr, "path_tool_control: end\n");
  1399. #endif PATH_TOOL_DEBUG
  1400. }
  1401.  
  1402. Tool *
  1403. tools_new_path_tool (void)
  1404. {
  1405.    Tool * tool;
  1406.    PathTool * private;
  1407.  
  1408.    /*  The tool options  */
  1409.    if (! path_options)
  1410.       {
  1411.          path_options = tool_options_new (_("Path Tool"));
  1412.          tools_register (PATH_TOOL, (ToolOptions *) path_options);
  1413.       }
  1414.  
  1415.    tool = tools_new_tool (PATH_TOOL);
  1416.    private = g_new0 (PathTool, 1);
  1417.  
  1418.    private->click_type       = ON_CANVAS;
  1419.    private->click_x         = 0;
  1420.    private->click_y         = 0;
  1421.    private->click_halfwidth = 0;
  1422.    private->click_modifier  = 0;
  1423.    private->click_path      = NULL;
  1424.    private->click_curve     = NULL;
  1425.    private->click_segment   = NULL;
  1426.    private->click_position  = -1;
  1427.  
  1428.    private->active_count    = 0;
  1429.    private->single_active_segment = NULL;
  1430.  
  1431.    private->state           = 0;
  1432.    private->draw            = PATH_TOOL_REDRAW_ALL;
  1433.    private->core            = draw_core_new (path_tool_draw);
  1434.    private->cur_path        = g_new0(Path, 1);
  1435.    private->scanlines       = NULL;
  1436.  
  1437.  
  1438.    tool->private = (void *) private;
  1439.  
  1440.    tool->button_press_func   = path_tool_button_press;
  1441.    tool->button_release_func = path_tool_button_release;
  1442.    tool->motion_func         = path_tool_motion;
  1443.    tool->cursor_update_func  = path_tool_cursor_update;
  1444.    tool->control_func        = path_tool_control;
  1445.  
  1446.    private->cur_path->curves    = NULL;
  1447.    private->cur_path->cur_curve = NULL;
  1448.    private->cur_path->name      = g_string_new("Path 0");
  1449.    private->cur_path->state     = 0;
  1450.    private->cur_path->path_tool = private;
  1451.    
  1452.    return tool;
  1453. }
  1454.  
  1455. void
  1456. tools_free_path_tool (Tool *tool)
  1457. {
  1458.    GDisplay * gdisp;
  1459.    PathTool * path_tool;
  1460.  
  1461. #ifdef PATH_TOOL_DEBUG
  1462.    fprintf (stderr, "tools_free_path_tool start\n");
  1463. #endif PATH_TOOL_DEBUG
  1464.    path_tool = (PathTool *) tool->private;
  1465.    gdisp = (GDisplay *) tool->gdisp_ptr;
  1466.  
  1467.    if (tool->state == ACTIVE)
  1468.    {
  1469.       draw_core_stop (path_tool->core, tool);
  1470.    }
  1471.    
  1472.    path_free_path (path_tool->cur_path);
  1473.  
  1474.    draw_core_free (path_tool->core);
  1475.    
  1476.    g_free (path_tool);
  1477. #ifdef PATH_TOOL_DEBUG
  1478.    fprintf (stderr, "tools_free_path_tool end\n");
  1479. #endif PATH_TOOL_DEBUG
  1480.  
  1481. }
  1482.  
  1483.  
  1484. /**************************************************************
  1485.  * Set of function to determine, if the click was on a segment
  1486.  */
  1487.  
  1488. typedef struct {
  1489.    Tool *tool;
  1490.    Path *path;
  1491.    PathCurve *curve;
  1492.    PathSegment *segment;
  1493.    gint testx;
  1494.    gint testy;
  1495.    gint halfwidth;
  1496.    gint distance;
  1497.    gdouble position;
  1498.    gboolean found;
  1499. } Path_on_curve_type;
  1500.  
  1501. /* This is a CurveTraverseFunc */
  1502. void
  1503. path_tool_on_curve_helper (Path *path,
  1504.                PathCurve *curve,
  1505.                PathSegment *segment,
  1506.                gpointer ptr)
  1507. {
  1508.    gint distance;
  1509.    gdouble position;
  1510.    Path_on_curve_type *data = (Path_on_curve_type *) ptr;
  1511.  
  1512.    if (segment && segment->next && data && data->distance > 0)
  1513.    {
  1514.       position = path_curve_on_segment (data->tool, segment, data->testx, data->testy, data->halfwidth, &distance);
  1515.       if (position >= 0 && distance < data->distance )
  1516.       {
  1517.          data->path = path;
  1518.          data->curve = curve;
  1519.          data->segment = segment;
  1520.      data->distance = distance;
  1521.      data->position = position;
  1522.      data->found = TRUE;
  1523.       }
  1524.    }
  1525. }
  1526.  
  1527. gdouble
  1528. path_tool_on_curve (Tool *tool,
  1529.             gint x,
  1530.             gint y,
  1531.             gint halfwidth,
  1532.             Path **ret_pathP,
  1533.             PathCurve **ret_curveP,
  1534.             PathSegment **ret_segmentP)
  1535. {
  1536.    Path_on_curve_type *data = g_new (Path_on_curve_type, 1);
  1537.    gdouble position;
  1538.  
  1539.    data->tool = tool;
  1540.    data->path = NULL;
  1541.    data->segment = NULL;
  1542.    data->segment = NULL;
  1543.    data->testx = x;
  1544.    data->testy = y;
  1545.    data->halfwidth = halfwidth;
  1546.    data->distance = halfwidth * halfwidth + 1;
  1547.    data->position = -1;
  1548.    data->found = FALSE;
  1549.  
  1550.    path_traverse_path (((PathTool *) data->tool->private)->cur_path, NULL, path_tool_on_curve_helper, NULL, data);
  1551.  
  1552.    if (ret_pathP) *ret_pathP = data->path;
  1553.    if (ret_curveP) *ret_curveP = data->curve;
  1554.    if (ret_segmentP) *ret_segmentP = data->segment;
  1555.  
  1556.    position = data->position;
  1557.  
  1558.    g_free(data);
  1559.  
  1560.    return position;
  1561.  
  1562. }
  1563.  
  1564. /**************************************************************
  1565.  * Set of function to determine, if the click was on an anchor
  1566.  */
  1567.  
  1568. typedef struct {
  1569.    Path *path;
  1570.    PathCurve *curve;
  1571.    PathSegment *segment;
  1572.    gint testx;
  1573.    gint testy;
  1574.    gint distance;
  1575.    gboolean found;
  1576. } Path_on_anchors_type;
  1577.  
  1578. /* This is a CurveTraverseFunc */
  1579. void
  1580. path_tool_on_anchors_helper (Path *path,
  1581.                  PathCurve *curve,
  1582.                  PathSegment *segment,
  1583.                  gpointer ptr)
  1584. {
  1585.    gint distance;
  1586.    Path_on_anchors_type *data = (Path_on_anchors_type *) ptr;
  1587.  
  1588.    if (segment && data && data->distance > 0)
  1589.    {
  1590.       distance = ((data->testx - segment->x) * (data->testx - segment->x) +
  1591.                   (data->testy - segment->y) * (data->testy - segment->y));
  1592.  
  1593.       if ( distance < data->distance )
  1594.       {
  1595.          data->path = path;
  1596.          data->curve = curve;
  1597.          data->segment = segment;
  1598.      data->distance = distance;
  1599.      data->found = TRUE;
  1600.       }
  1601.    }
  1602. }
  1603.  
  1604. gboolean
  1605. path_tool_on_anchors (Tool *tool,
  1606.               gint x,
  1607.               gint y,
  1608.               gint halfwidth,
  1609.               Path **ret_pathP,
  1610.               PathCurve **ret_curveP,
  1611.               PathSegment **ret_segmentP)
  1612. {
  1613.    Path_on_anchors_type *data = g_new (Path_on_anchors_type, 1);
  1614.    gboolean ret_found;
  1615.  
  1616.    data->path = NULL;
  1617.    data->curve = NULL;
  1618.    data->segment = NULL;
  1619.    data->testx = x;
  1620.    data->testy = y;
  1621.    data->distance = halfwidth * halfwidth + 1;
  1622.    data->found = FALSE;
  1623.  
  1624.    path_traverse_path (((PathTool *) tool->private)->cur_path, NULL, path_tool_on_anchors_helper, NULL, data);
  1625.  
  1626.    if (ret_pathP) *ret_pathP = data->path;
  1627.    if (ret_curveP) *ret_curveP = data->curve;
  1628.    if (ret_segmentP) *ret_segmentP = data->segment;
  1629.  
  1630.    ret_found = data->found;
  1631.  
  1632.    g_free(data);
  1633.  
  1634.    return ret_found;
  1635.  
  1636. }
  1637.  
  1638. /**************************************************************
  1639.  * Set of function to determine, if the click was on an handle
  1640.  */
  1641.  
  1642. typedef struct {
  1643.    Path *path;
  1644.    PathCurve *curve;
  1645.    PathSegment *segment;
  1646.    gint testx;
  1647.    gint testy;
  1648.    gint halfwidth;
  1649.    gint handle_id;
  1650.    gboolean found;
  1651. } Path_on_handles_type;
  1652.  
  1653. /* This is a CurveTraverseFunc */
  1654. void
  1655. path_tool_on_handles_helper (Path *path,
  1656.                  PathCurve *curve,
  1657.                  PathSegment *segment,
  1658.                  gpointer ptr)
  1659. {
  1660.    Path_on_handles_type *data = (Path_on_handles_type *) ptr;
  1661.    gint handle;
  1662.  
  1663.    if (segment && data && !data->found)
  1664.    {
  1665.       handle = path_curve_on_handle (NULL, segment, data->testx, data->testy,
  1666.        data->halfwidth);
  1667.       if (handle)
  1668.       {
  1669.          data->path = path;
  1670.          data->curve = curve;
  1671.          data->segment = segment;
  1672.      data->handle_id = handle;
  1673.      data->found = TRUE;
  1674.       }
  1675.    }
  1676. }
  1677.  
  1678. gint
  1679. path_tool_on_handles (Tool *tool,
  1680.               gint x,
  1681.               gint y,
  1682.               gint halfwidth,
  1683.               Path **ret_pathP,
  1684.               PathCurve **ret_curveP,
  1685.               PathSegment **ret_segmentP)
  1686. {
  1687.    Path_on_handles_type *data = g_new (Path_on_handles_type, 1);
  1688.    gint handle_ret;
  1689.  
  1690.    data->path = NULL;
  1691.    data->curve = NULL;
  1692.    data->segment = NULL;
  1693.    data->testx = x;
  1694.    data->testy = y;
  1695.    data->halfwidth = halfwidth;
  1696.    data->handle_id = 0;
  1697.    data->found = FALSE;
  1698.  
  1699.    path_traverse_path (((PathTool *) tool->private)->cur_path, NULL, path_tool_on_handles_helper, NULL, data);
  1700.  
  1701.    if (ret_pathP) *ret_pathP = data->path;
  1702.    if (ret_curveP) *ret_curveP = data->curve;
  1703.    if (ret_segmentP) *ret_segmentP = data->segment;
  1704.  
  1705.    handle_ret = data->handle_id;
  1706.  
  1707.    g_free(data);
  1708.  
  1709.    return handle_ret;
  1710. }
  1711.  
  1712.  
  1713. /**************************************************************
  1714.  * Set of function to offset all active anchors
  1715.  */
  1716.  
  1717. typedef struct {
  1718.    gdouble dx;
  1719.    gdouble dy;
  1720. } Path_offset_active_type;
  1721.  
  1722. /* This is a CurveTraverseFunc */
  1723. void
  1724. path_offset_active_helper (Path *path,
  1725.                PathCurve *curve,
  1726.                PathSegment *segment,
  1727.                gpointer ptr)
  1728. {
  1729.    Path_offset_active_type *data = (Path_offset_active_type *) ptr;
  1730.  
  1731.    if (segment && data && (segment->flags & SEGMENT_ACTIVE)) {
  1732.       segment->x += data->dx;
  1733.       segment->y += data->dy;
  1734.    }
  1735. /* XXX: Do a segment_update here! */
  1736. }
  1737.  
  1738. void
  1739. path_offset_active (Path *path,
  1740.             gdouble dx,
  1741.             gdouble dy)
  1742. {
  1743.    Path_offset_active_type *data = g_new (Path_offset_active_type, 1);
  1744.    data->dx = dx;
  1745.    data->dy = dy;
  1746.    
  1747.    if (path)
  1748.       path_traverse_path (path, NULL, path_offset_active_helper, NULL, data);
  1749.    
  1750.    g_free(data);
  1751. }
  1752.  
  1753.  
  1754. /**************************************************************
  1755.  * Set of function to set the state of all anchors
  1756.  */
  1757.  
  1758. typedef struct {
  1759.    guint32 bits_set;
  1760.    guint32 bits_clear;
  1761.    PathTool *path_tool;
  1762. } Path_set_flags_type;
  1763.  
  1764. /* This is a CurveTraverseFunc */
  1765. void
  1766. path_set_flags_helper (Path *path,
  1767.                PathCurve *curve,
  1768.                PathSegment *segment,
  1769.                gpointer ptr)
  1770. {
  1771.    Path_set_flags_type *tmp = (Path_set_flags_type *) ptr;
  1772.    guint32 oldflags;
  1773.    guint tmp_uint;
  1774.  
  1775.    if (segment) {
  1776.       oldflags = segment->flags;
  1777.       segment->flags &= ~(tmp->bits_clear);
  1778.       segment->flags |= tmp->bits_set;
  1779.  
  1780.       /* 
  1781.        * Some black magic: We try to remember, which is the single active segment.
  1782.        * We count, how many segments are active (in path_tool->active_count) and
  1783.        * XOR path_tool->single_active_segment every time we select or deselect
  1784.        * an anchor. So if exactly one anchor is active, path_tool->single_active_segment
  1785.        * points to it.
  1786.        */
  1787.  
  1788.       /* If SEGMENT_ACTIVE state has changed change the PathTool data accordingly.*/
  1789.       if (((segment->flags ^ oldflags) & SEGMENT_ACTIVE) && tmp && tmp->path_tool) {
  1790.      if (segment->flags & SEGMENT_ACTIVE)
  1791.         tmp->path_tool->active_count++;
  1792.      else
  1793.         tmp->path_tool->active_count--;
  1794.  
  1795.      /* Does this work on all (16|32|64)-bit Machines? */
  1796.  
  1797.      tmp_uint = GPOINTER_TO_UINT(tmp->path_tool->single_active_segment);
  1798.          tmp_uint ^= GPOINTER_TO_UINT(segment);
  1799.      tmp->path_tool->single_active_segment = GUINT_TO_POINTER(tmp_uint);
  1800.       }
  1801.    }
  1802. }
  1803.  
  1804. void
  1805. path_set_flags (PathTool *path_tool,
  1806.         Path *path,
  1807.         PathCurve *curve,
  1808.         PathSegment *segment,
  1809.         guint32 bits_set,
  1810.         guint32 bits_clear)
  1811. {
  1812.    Path_set_flags_type *tmp = g_new (Path_set_flags_type, 1);
  1813.    tmp->bits_set=bits_set;
  1814.    tmp->bits_clear=bits_clear;
  1815.    tmp->path_tool = path_tool;
  1816.  
  1817.    if (segment)
  1818.       path_set_flags_helper (path, curve, segment, tmp);
  1819.    else if (curve)
  1820.       path_traverse_curve (path, curve, path_set_flags_helper, NULL, tmp);
  1821.    else if (path)
  1822.       path_traverse_path (path, NULL, path_set_flags_helper, NULL, tmp);
  1823.  
  1824.    g_free (tmp);
  1825. }
  1826.  
  1827.  
  1828. /**************************************************************
  1829.  * Set of functions to draw the segments to the window
  1830.  */
  1831.  
  1832. /* This is a CurveTraverseFunc */
  1833. void
  1834. path_tool_draw_helper (Path *path,
  1835.                PathCurve *curve,
  1836.                PathSegment *segment,
  1837.                gpointer tool_ptr)
  1838. {
  1839.    Tool     * tool = (Tool *) tool_ptr;
  1840.    GDisplay * gdisp;
  1841.    PathTool * path_tool;
  1842.    DrawCore * core;
  1843.    gint x1, y1;
  1844.    gboolean draw = TRUE;
  1845.    
  1846.    if (!tool) {
  1847. #ifdef PATH_TOOL_DEBUG
  1848.       fprintf (stderr, "Fatal Error: path_tool_draw_segment called without valid tool *\n");
  1849. #endif PATH_TOOL_DEBUG
  1850.       return;
  1851.    }
  1852.    
  1853.    gdisp = tool->gdisp_ptr;
  1854.  
  1855.    path_tool = (PathTool *) tool->private;
  1856.    core = path_tool->core;
  1857.    
  1858.    if (path_tool->draw & PATH_TOOL_REDRAW_ACTIVE)
  1859.       draw = (segment->flags & SEGMENT_ACTIVE || (segment->next && segment->next->flags & SEGMENT_ACTIVE));
  1860.  
  1861.    if (segment && draw) 
  1862.    {
  1863.       gdisplay_transform_coords (gdisp, (gint) segment->x, (gint) segment->y, &x1, &y1, FALSE);
  1864.       if (segment->flags & SEGMENT_ACTIVE)
  1865.          gdk_draw_arc (core->win, core->gc, 0,
  1866.                    x1 - PATH_TOOL_HALFWIDTH, y1 - PATH_TOOL_HALFWIDTH,
  1867.                PATH_TOOL_WIDTH, PATH_TOOL_WIDTH, 0, 23040);
  1868.       else
  1869.          gdk_draw_arc (core->win, core->gc, 1,
  1870.                    x1 - PATH_TOOL_HALFWIDTH, y1 - PATH_TOOL_HALFWIDTH,
  1871.                PATH_TOOL_WIDTH, PATH_TOOL_WIDTH, 0, 23040);
  1872.       
  1873.       path_curve_draw_handles (tool, segment);
  1874.    
  1875.       if (segment->next)
  1876.       {
  1877.          path_curve_draw_segment (tool, segment);
  1878.       }
  1879.    }
  1880. #ifdef PATH_TOOL_DEBUG
  1881.    else if (!segment)
  1882.       fprintf(stderr, "path_tool_draw_segment: no segment to draw\n");
  1883. #endif PATH_TOOL_DEBUG
  1884. }
  1885.  
  1886. void
  1887. path_tool_draw (Tool *tool)
  1888. {
  1889.    GDisplay * gdisp;
  1890.    Path * cur_path;
  1891.    PathTool * path_tool;
  1892.   
  1893. #ifdef PATH_TOOL_DEBUG
  1894.    fprintf (stderr, "path_tool_draw\n");
  1895. #endif PATH_TOOL_DEBUG
  1896.    
  1897.    gdisp = tool->gdisp_ptr;
  1898.    path_tool = tool->private;
  1899.    cur_path = path_tool->cur_path;
  1900.    
  1901.    path_traverse_path (cur_path, NULL, path_tool_draw_helper, NULL, tool);
  1902.    
  1903. #ifdef PATH_TOOL_DEBUG
  1904.    /* fprintf (stderr, "path_tool_draw end.\n");
  1905.     */
  1906. #endif PATH_TOOL_DEBUG
  1907.    
  1908. }
  1909.  
  1910.  
  1911.