home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / paths_dialog.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  70.1 KB  |  2,732 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1999 Andy Thomas alt@picnic.demon.co.uk
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  * Some of this code is based on the layers_dialog box code.
  18.  */
  19.  
  20. #include "config.h"
  21.  
  22. #include <stdio.h>
  23. #include <errno.h>
  24. #include <string.h>
  25.  
  26. #include <gtk/gtk.h>
  27. #include <gdk/gdkkeysyms.h>
  28.  
  29. #include "apptypes.h"
  30.  
  31. #include "appenv.h"
  32. #include "draw_core.h"
  33. #include "drawable.h"
  34. #include "floating_sel.h"
  35. #include "gimage.h"
  36. #include "gimpimage.h"
  37. #include "gimpdrawable.h"
  38. #include "gimage_mask.h"
  39. #include "gdisplay.h"
  40. #include "gimprc.h"
  41. #include "gimpset.h"
  42. #include "gimpui.h"
  43. #include "image_render.h"
  44. #include "lc_dialogP.h"
  45. #include "menus.h"
  46. #include "ops_buttons.h"
  47. #include "bezier_select.h"
  48. #include "bezier_selectP.h"
  49. #include "path.h"
  50. #include "pathP.h"
  51. #include "path_transform.h"
  52. #include "paths_dialog.h"
  53. #include "paths_dialogP.h"
  54. #include "undo.h"
  55.  
  56. #include "drawable_pvt.h"
  57.  
  58. #include "libgimp/gimpmath.h"
  59.  
  60. #include "libgimp/gimpintl.h"
  61.  
  62. #include "pixmaps/new.xpm"
  63. #include "pixmaps/duplicate.xpm"
  64. #include "pixmaps/delete.xpm"
  65. #include "pixmaps/pennorm.xpm"
  66. #include "pixmaps/penadd.xpm"
  67. #include "pixmaps/pendel.xpm"
  68. #include "pixmaps/penedit.xpm"
  69. #include "pixmaps/penstroke.xpm"
  70. #include "pixmaps/toselection.xpm"
  71. #include "pixmaps/topath.xpm"
  72. #include "pixmaps/path.xbm"
  73. #include "pixmaps/locked.xbm"
  74.  
  75. typedef struct _PathsDialog PathsDialog;
  76.  
  77. struct _PathsDialog
  78. {
  79.   GtkWidget *vbox;
  80.   GtkWidget *paths_list;
  81.  
  82.   GtkWidget     *ops_menu;
  83.   GtkAccelGroup *accel_group;
  84.  
  85.   gdouble ratio;
  86.   gint    image_width, image_height;
  87.   gint    gimage_width, gimage_height;
  88.  
  89.   /* pixmaps for the no preview bitmap */
  90.   GdkPixmap *pixmap_normal;
  91.   GdkPixmap *pixmap_selected;
  92.   GdkPixmap *pixmap_locked_normal;
  93.   GdkPixmap *pixmap_locked_selected;
  94.  
  95.   /*  state information  */
  96.   gint       selsigid;
  97.   GimpImage *gimage;
  98.   GdkGC     *gc;   
  99.   GdkColor   black;
  100.   GdkColor   white;
  101.   gint       selected_row_num;
  102.   gboolean   been_selected;
  103.   PathList  *current_path_list;
  104. };
  105.  
  106. typedef struct _PathWidget PathWidget;
  107.  
  108. struct _PathWidget
  109. {
  110.   GdkPixmap *paths_pixmap;
  111.   Path      *bzp;
  112. };
  113.  
  114. typedef struct _PathCounts PathCounts;
  115.  
  116. struct _PathCounts
  117. {
  118.   CountCurves  c_count;             /* Must be the first element */
  119.   gint         total_count;         /* Total number of curves    */
  120. };
  121.  
  122. static PathsDialog *paths_dialog = NULL;
  123. static Path        *copy_pp      = NULL;
  124.  
  125. static void     paths_dialog_realized        (GtkWidget      *widget);
  126. static void     paths_select_row             (GtkWidget      *widget,
  127.                           gint            row,
  128.                           gint            column, 
  129.                           GdkEventButton *event,
  130.                           gpointer        data);
  131. static void     paths_unselect_row           (GtkWidget      *widget,
  132.                           gint            row,
  133.                           gint            column,
  134.                           GdkEventButton *event,
  135.                           gpointer        data);
  136. static gint     paths_list_events            (GtkWidget      *widget,
  137.                           GdkEvent       *event);
  138. static void     paths_dialog_map_callback    (GtkWidget      *widget,
  139.                           gpointer        data);
  140. static void     paths_dialog_unmap_callback  (GtkWidget      *widget,
  141.                           gpointer        data);
  142. static void     paths_update_paths           (gpointer        data,
  143.                           gint            row);
  144. static void     paths_update_preview         (BezierSelect   *bezier_sel);
  145. static void     paths_dialog_preview_extents           (void);
  146. static void     paths_dialog_new_point_callback        (GtkWidget *, gpointer);
  147. static void     paths_dialog_add_point_callback        (GtkWidget *, gpointer);
  148. static void     paths_dialog_delete_point_callback     (GtkWidget *, gpointer);
  149. static void     paths_dialog_edit_point_callback       (GtkWidget *, gpointer);
  150. static void     paths_dialog_advanced_to_path_callback (GtkWidget *, gpointer);
  151. static void     paths_dialog_null_callback             (GtkWidget *, gpointer);
  152.  
  153. static void     path_close                   (Path *);
  154.  
  155. /*  the ops buttons  */
  156. static GtkSignalFunc to_path_ext_callbacks[] = 
  157.   paths_dialog_advanced_to_path_callback,          /* SHIFT */
  158.   paths_dialog_null_callback,                      /* CTRL  */
  159.   paths_dialog_null_callback,                      /* MOD1  */
  160.   paths_dialog_null_callback,                      /* SHIFT + CTRL */
  161. };
  162.  
  163. static OpsButton paths_ops_buttons[] =
  164. {
  165.   { new_xpm, paths_dialog_new_path_callback, NULL,
  166.     N_("New Path"),
  167.     "paths/new_path.html",
  168.     NULL, 0 },
  169.   { duplicate_xpm, paths_dialog_dup_path_callback, NULL,
  170.     N_("Duplicate Path"),
  171.     "paths/duplicate_path.html",
  172.     NULL, 0 },
  173.   { toselection_xpm, paths_dialog_path_to_sel_callback, NULL,
  174.     N_("Path to Selection"),
  175.     "paths/path_to_selection.html",
  176.     NULL, 0 },
  177.   { topath_xpm, paths_dialog_sel_to_path_callback, to_path_ext_callbacks,
  178.     N_("Selection to Path"),
  179.     "filters/sel2path.html",
  180.     NULL, 0 },
  181.   { penstroke_xpm, paths_dialog_stroke_path_callback, NULL,
  182.     N_("Stroke Path"),
  183.     "paths/stroke_path.html",
  184.     NULL, 0 },
  185.   { delete_xpm, paths_dialog_delete_path_callback, NULL,
  186.     N_("Delete Path"),
  187.     "paths/delete_path.html",
  188.     NULL, 0 },
  189.   { NULL, NULL, NULL, NULL, NULL, NULL, 0 }
  190. };
  191.  
  192. static OpsButton point_ops_buttons[] =
  193. {
  194.   { pennorm_xpm, paths_dialog_new_point_callback, NULL,
  195.     N_("New Point"),
  196.     "#new_point_button",
  197.     NULL, 0 },
  198.   { penadd_xpm, paths_dialog_add_point_callback, NULL,
  199.     N_("Add Point"),
  200.     "#add_point_button",
  201.     NULL, 0 },
  202.   { pendel_xpm, paths_dialog_delete_point_callback, NULL,
  203.     N_("Delete Point"),
  204.     "#delete_point_button",
  205.     NULL, 0 },
  206.   { penedit_xpm, paths_dialog_edit_point_callback, NULL,
  207.     N_("Edit Point"),
  208.     "#edit_point_button",
  209.     NULL, 0 },
  210.   { NULL, NULL, NULL, NULL, NULL, NULL, 0 }
  211. };
  212.  
  213. static void
  214. paths_dialog_set_menu_sensitivity (void)
  215. {
  216.   gboolean gimage = FALSE;  /*  is there a gimage  */
  217.   gboolean pp     = FALSE;  /*  paths present  */
  218.   gboolean cpp    = FALSE;  /*  is there a path in the pate buffer  */
  219.  
  220.   if (! paths_dialog)
  221.     return;
  222.  
  223.   if (paths_dialog->gimage)
  224.     gimage = TRUE;
  225.  
  226.   if (gimage && gimp_image_get_paths (paths_dialog->gimage))
  227.     pp = TRUE;
  228.  
  229.   if (copy_pp)
  230.     cpp = TRUE;
  231.  
  232. #define SET_SENSITIVE(menu,condition) \
  233.         menus_set_sensitive ("<Paths>/" menu, (condition) != 0)
  234. #define SET_OPS_SENSITIVE(button,condition) \
  235.         gtk_widget_set_sensitive (paths_ops_buttons[(button)].widget, \
  236.                                  (condition) != 0)
  237. #define SET_POINT_SENSITIVE(button,condition) \
  238.         gtk_widget_set_sensitive (point_ops_buttons[(button)].widget, \
  239.                                  (condition) != 0)
  240.  
  241.   SET_SENSITIVE ("New Path", gimage);
  242.   SET_OPS_SENSITIVE (0, gimage);
  243.  
  244.   SET_SENSITIVE ("Duplicate Path", pp);
  245.   SET_OPS_SENSITIVE (1, pp);
  246.  
  247.   SET_SENSITIVE ("Path to Selection", pp);
  248.   SET_OPS_SENSITIVE (2, pp);
  249.  
  250.   SET_SENSITIVE ("Selection to Path", gimage);
  251.   SET_OPS_SENSITIVE (3, gimage);
  252.  
  253.   SET_SENSITIVE ("Stroke Path", pp);
  254.   SET_OPS_SENSITIVE (4, pp);
  255.  
  256.   SET_SENSITIVE ("Delete Path", pp);
  257.   SET_OPS_SENSITIVE (5, pp);
  258.  
  259.   SET_SENSITIVE ("Copy Path", pp);
  260.   SET_SENSITIVE ("Paste Path", pp && cpp);
  261.  
  262.   SET_SENSITIVE ("Import Path...", gimage);
  263.   SET_SENSITIVE ("Export Path...", pp);
  264.  
  265.   SET_SENSITIVE ("Edit Path Attributes...", pp);
  266.  
  267.   /*  new point  */
  268.   SET_POINT_SENSITIVE (0, pp);
  269.  
  270.   /*  add point  */
  271.   SET_POINT_SENSITIVE (1, pp);
  272.  
  273.   /*  selete point  */
  274.   SET_POINT_SENSITIVE (2, pp);
  275.  
  276.   /*  edit point  */
  277.   SET_POINT_SENSITIVE (3, pp);
  278.  
  279. #undef SET_POINT_SENSITIVE
  280. #undef SET_OPS_SENSITIVE
  281. #undef SET_SENSITIVE
  282. }
  283.  
  284. void
  285. paths_dialog_set_default_op (void)
  286. {
  287.   if(paths_dialog != NULL) /* Bug #5049: Clients may call this because it is possible */
  288.                            /* to create a path before the L&C dialog exists.          */
  289.  
  290.     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (point_ops_buttons[0].widget),
  291.                    TRUE);
  292. }
  293.  
  294. GtkWidget *
  295. paths_dialog_create (void)
  296. {
  297.   GtkWidget *vbox;
  298.   GtkWidget *paths_list;
  299.   GtkWidget *scrolled_win;  
  300.   GtkWidget *button_box;  
  301.  
  302.   if (paths_dialog)
  303.     return paths_dialog->vbox;
  304.  
  305.   paths_dialog = g_new0 (PathsDialog, 1);
  306.  
  307.   /*  The paths box  */
  308.   paths_dialog->vbox = gtk_event_box_new ();
  309.  
  310.   gimp_help_set_help_data (paths_dialog->vbox, NULL,
  311.                "dialogs/paths/paths.html");
  312.  
  313.   vbox = gtk_vbox_new (FALSE, 1);
  314.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
  315.   gtk_container_add (GTK_CONTAINER (paths_dialog->vbox), vbox);
  316.  
  317.   /* The point operations */
  318.   button_box = ops_button_box_new (point_ops_buttons, OPS_BUTTON_RADIO);
  319.   gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, TRUE, 2);
  320.   gtk_widget_show (button_box);
  321.  
  322.   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
  323.   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
  324.                   GTK_POLICY_AUTOMATIC,
  325.                   GTK_POLICY_ALWAYS);
  326.   gtk_widget_set_usize (scrolled_win, LIST_WIDTH, LIST_HEIGHT);
  327.   gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 2);
  328.  
  329.   paths_dialog->paths_list = paths_list = gtk_clist_new (2);
  330.   gtk_signal_connect (GTK_OBJECT (vbox), "destroy",
  331.               GTK_SIGNAL_FUNC (gtk_widget_destroyed),
  332.               &paths_dialog);
  333.  
  334.   gtk_clist_set_selection_mode (GTK_CLIST (paths_list), GTK_SELECTION_BROWSE);
  335.   gtk_clist_set_reorderable (GTK_CLIST (paths_list), FALSE);
  336.   gtk_clist_set_column_width (GTK_CLIST (paths_list), 0, locked_width);
  337.   gtk_clist_set_column_min_width (GTK_CLIST (paths_list), 1, 
  338.                   LIST_WIDTH - locked_width - 4);
  339.   gtk_clist_set_column_auto_resize (GTK_CLIST (paths_list), 1, TRUE);
  340.  
  341.   gtk_container_add (GTK_CONTAINER (scrolled_win), paths_list);
  342.   gtk_signal_connect (GTK_OBJECT (paths_list), "event",
  343.               (GtkSignalFunc) paths_list_events,
  344.               paths_dialog);
  345.   gtk_container_set_focus_vadjustment (GTK_CONTAINER (paths_list), 
  346.                        gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (scrolled_win))); 
  347.   GTK_WIDGET_UNSET_FLAGS (GTK_SCROLLED_WINDOW (scrolled_win)->vscrollbar,
  348.               GTK_CAN_FOCUS); 
  349.  
  350.   paths_dialog->selsigid =
  351.     gtk_signal_connect (GTK_OBJECT (paths_list), "select_row",
  352.             GTK_SIGNAL_FUNC (paths_select_row),
  353.             NULL);
  354.  
  355.   gtk_signal_connect (GTK_OBJECT (paths_list), "unselect_row",
  356.               GTK_SIGNAL_FUNC (paths_unselect_row),
  357.               NULL);
  358.       
  359.   gtk_widget_show (scrolled_win);
  360.   gtk_widget_show (paths_list);
  361.  
  362.   gtk_signal_connect (GTK_OBJECT (paths_dialog->vbox), "realize",
  363.               GTK_SIGNAL_FUNC (paths_dialog_realized),
  364.               NULL);
  365.  
  366.   gtk_widget_show (vbox);
  367.   gtk_widget_show (paths_dialog->vbox);
  368.  
  369.   /*  The ops buttons  */
  370.   button_box = ops_button_box_new (paths_ops_buttons, OPS_BUTTON_NORMAL);
  371.   gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 2);
  372.   gtk_widget_show (button_box);
  373.  
  374.   menus_get_paths_menu (&paths_dialog->ops_menu,
  375.             &paths_dialog->accel_group);
  376.  
  377.   /*  Set up signals for map/unmap for the accelerators  */
  378.   gtk_signal_connect (GTK_OBJECT (vbox), "map",
  379.               (GtkSignalFunc) paths_dialog_map_callback,
  380.               NULL);
  381.   gtk_signal_connect (GTK_OBJECT (vbox), "unmap",
  382.               (GtkSignalFunc) paths_dialog_unmap_callback,
  383.               NULL);
  384.  
  385.   paths_dialog_set_menu_sensitivity ();
  386.  
  387.   paths_dialog_set_default_op ();
  388.   
  389.   return paths_dialog->vbox;
  390. }
  391.  
  392. static void 
  393. paths_dialog_realized (GtkWidget *widget)
  394. {
  395.   GdkColormap *colormap;
  396.   gchar dash_list[2]= {3,3};
  397.  
  398.   /* Help out small displays */
  399.   if (preview_size < 64)
  400.     dash_list[1] = 1;
  401.  
  402.   paths_dialog->gc = gdk_gc_new (widget->window);
  403.   gdk_gc_set_dashes (paths_dialog->gc, 2, dash_list, 2);
  404.   colormap = gtk_widget_get_colormap (paths_dialog->paths_list);
  405.   gdk_color_parse ("black", &paths_dialog->black);
  406.   gdk_color_alloc (colormap, &paths_dialog->black);
  407.   gdk_color_parse ("white", &paths_dialog->white);
  408.   gdk_color_alloc (colormap, &paths_dialog->white);
  409. }
  410.  
  411. /* Clears out row when list element is deleted/destroyed */
  412. static void
  413. clear_pathwidget (gpointer data)
  414. {
  415.   PathWidget *pwidget = data;
  416.  
  417.   if (pwidget)
  418.     {
  419.       if (pwidget->paths_pixmap)
  420.     gdk_pixmap_unref (pwidget->paths_pixmap);
  421.  
  422.       g_free (pwidget);
  423.     }
  424. }
  425.  
  426.  
  427. static Path*
  428. path_dialog_new (GimpImage *gimage,
  429.          gint       name_seed, 
  430.          gpointer   data)
  431. {
  432.   Path  *bzp;
  433.   gchar *s;
  434.  
  435.   s = g_strdup_printf (_("Path %d"), name_seed);
  436.   bzp = path_new (gimage, BEZIER, (GSList *) data, 0, 0, 0, 0, s);
  437.  
  438.   return bzp;
  439. }
  440.  
  441. static PathPoint*
  442. path_start_last_seg (GSList *plist)
  443. {
  444.   PathPoint *retp = plist->data;
  445.   while (plist)
  446.     {
  447.       if (((PathPoint*) (plist->data))->type == BEZIER_MOVE &&
  448.       g_slist_next (plist))
  449.     {
  450.       plist = g_slist_next (plist);
  451.       retp = plist->data;
  452.     }
  453.       plist = g_slist_next (plist);
  454.     }  
  455.   return retp;
  456. }
  457.  
  458. static void
  459. path_close (Path *bzp)
  460. {
  461.   PathPoint *pdata;
  462.   PathPoint *pathpoint;
  463.  
  464.   /* bzpaths are only really closed when converted to the BezierSelect ones */
  465.   bzp->closed = 1;
  466.   /* first point */
  467.   pdata = (PathPoint*)bzp->path_details->data;
  468.  
  469.   if (g_slist_length (bzp->path_details) < 5)
  470.     {
  471.       int i;
  472.       for (i = 0 ; i < 2 ; i++)
  473.     {
  474.       pathpoint = g_new0 (PathPoint, 1);
  475.       pathpoint->type = (i & 1) ? BEZIER_ANCHOR : BEZIER_CONTROL;
  476.       pathpoint->x = pdata->x+i;
  477.       pathpoint->y = pdata->y+i;
  478.  
  479.       bzp->path_details = g_slist_append (bzp->path_details, pathpoint);
  480.     }
  481.     }
  482.   pathpoint = g_new0 (PathPoint, 1);
  483.   pdata = path_start_last_seg (bzp->path_details);
  484.   pathpoint->type = BEZIER_CONTROL;
  485.   pathpoint->x = pdata->x;
  486.   pathpoint->y = pdata->y;
  487.   /* printf("Closing to x,y %d,%d\n",(gint)pdata->x,(gint)pdata->y); */
  488.   bzp->path_details = g_slist_append (bzp->path_details, pathpoint);
  489.   bzp->state = BEZIER_EDIT;
  490. }
  491.  
  492. static void 
  493. bz_change_name_row_to (gint   row,
  494.                gchar *text)
  495. {
  496.   PathWidget *pwidget;
  497.  
  498.   pwidget = (PathWidget *)
  499.     gtk_clist_get_row_data (GTK_CLIST (paths_dialog->paths_list), row);
  500.  
  501.   if (!pwidget)
  502.     return;
  503.  
  504.   g_free (pwidget->bzp->name);
  505.  
  506.   pwidget->bzp->name = g_strdup (text);
  507. }
  508.  
  509. static void 
  510. paths_set_dash_line (GdkGC    *gc,
  511.              gboolean  state)
  512. {
  513.   gdk_gc_set_foreground (paths_dialog->gc, &paths_dialog->black);
  514.  
  515.   if (state)
  516.     {
  517.       gdk_gc_set_line_attributes (gc, 0, GDK_LINE_ON_OFF_DASH,
  518.                   GDK_CAP_BUTT, GDK_JOIN_ROUND);
  519.     }
  520.   else
  521.     {
  522.       gdk_gc_set_line_attributes (gc, 0, GDK_LINE_SOLID,
  523.                   GDK_CAP_BUTT, GDK_JOIN_ROUND);
  524.     }
  525. }
  526.  
  527. static void 
  528. clear_pixmap_preview (PathWidget *pwidget)
  529. {
  530.   guchar *rgb_buf;
  531.  
  532.   rgb_buf = g_new0 (guchar,
  533.             (paths_dialog->image_width + 4)
  534.             *(paths_dialog->image_height + 4) * 3);
  535.  
  536.   memset (rgb_buf,0xFF,(paths_dialog->image_width + 4)
  537.       *(paths_dialog->image_height + 4) * 3);
  538.  
  539.   gdk_draw_rgb_image (pwidget->paths_pixmap,
  540.               paths_dialog->gc,
  541.               0,
  542.               0,
  543.               paths_dialog->image_width + 4,
  544.               paths_dialog->image_height + 4,
  545.               GDK_RGB_DITHER_NORMAL,
  546.               rgb_buf,
  547.               (paths_dialog->image_width + 4)*3);
  548.  
  549.   paths_set_dash_line (paths_dialog->gc,FALSE);
  550.  
  551.   gdk_draw_rectangle (pwidget->paths_pixmap, 
  552.               paths_dialog->gc, FALSE, 0, 0, 
  553.               paths_dialog->image_width+3,
  554.               paths_dialog->image_height+3);
  555.  
  556.   gdk_draw_rectangle (pwidget->paths_pixmap, 
  557.               paths_dialog->gc, FALSE, 1, 1, 
  558.               paths_dialog->image_width+1,
  559.               paths_dialog->image_height+1);
  560.  
  561.   g_free (rgb_buf);
  562. }
  563.  
  564. /* insrow == -1 -> append else insert at insrow */
  565. void 
  566. paths_add_path (Path *bzp,
  567.         gint  insrow)
  568. {
  569.   /* Create a new entry in the list */
  570.   PathWidget *pwidget;
  571.   gint row;
  572.   gchar *row_data[2];
  573.  
  574.   pwidget = g_new0 (PathWidget, 1);
  575.  
  576.   if (!GTK_WIDGET_REALIZED (paths_dialog->vbox))
  577.     gtk_widget_realize (paths_dialog->vbox);
  578.  
  579.   paths_dialog_preview_extents ();
  580.  
  581.   if (preview_size)
  582.     {
  583.       /* Need to add this to the list */
  584.       pwidget->paths_pixmap =  gdk_pixmap_new (paths_dialog->vbox->window,
  585.                            paths_dialog->image_width + 4,  
  586.                            paths_dialog->image_height + 4,
  587.                            -1);
  588.       clear_pixmap_preview (pwidget);
  589.     }
  590.   else
  591.     {
  592.       if (!paths_dialog->pixmap_normal)
  593.     {
  594.       paths_dialog->pixmap_normal =
  595.         gdk_pixmap_create_from_data (paths_dialog->vbox->window,
  596.                      path_bits, 
  597.                      paths_dialog->image_width,
  598.                      paths_dialog->image_height,
  599.                      -1,
  600.                      &paths_dialog->vbox->style->fg[GTK_STATE_SELECTED],
  601.                      &paths_dialog->vbox->style->bg[GTK_STATE_SELECTED]);
  602.       paths_dialog->pixmap_selected =
  603.         gdk_pixmap_create_from_data (paths_dialog->vbox->window,
  604.                      path_bits, 
  605.                      paths_dialog->image_width,
  606.                      paths_dialog->image_height,
  607.                      -1,
  608.                      &paths_dialog->vbox->style->fg[GTK_STATE_NORMAL],
  609.                      &paths_dialog->vbox->style->bg[GTK_STATE_SELECTED]);
  610.     }
  611.        pwidget->paths_pixmap = paths_dialog->pixmap_normal;
  612.     }
  613.  
  614.   if (!paths_dialog->pixmap_locked_normal)
  615.     {
  616.       paths_dialog->pixmap_locked_normal = 
  617.     gdk_pixmap_create_from_data (paths_dialog->vbox->window,
  618.                      locked_bits, locked_width, locked_height, -1,
  619.                      &paths_dialog->vbox->style->fg[GTK_STATE_NORMAL],
  620.                      &paths_dialog->vbox->style->white);
  621.       paths_dialog->pixmap_locked_selected = 
  622.     gdk_pixmap_create_from_data (paths_dialog->vbox->window,
  623.                      locked_bits, locked_width, locked_height, -1,
  624.                      &paths_dialog->vbox->style->fg[GTK_STATE_SELECTED],
  625.                      &paths_dialog->vbox->style->bg[GTK_STATE_SELECTED]);
  626.     }
  627.  
  628.   gtk_clist_set_row_height (GTK_CLIST (paths_dialog->paths_list),
  629.                 paths_dialog->image_height + 6);
  630.  
  631.   row_data[0] = "";
  632.   row_data[1] = "";
  633.  
  634.   if (insrow == -1)
  635.     row = gtk_clist_append (GTK_CLIST (paths_dialog->paths_list),
  636.                 row_data);
  637.   else
  638.     row = gtk_clist_insert (GTK_CLIST (paths_dialog->paths_list),
  639.                 insrow,
  640.                 row_data);
  641.  
  642.   gtk_clist_set_pixtext (GTK_CLIST (paths_dialog->paths_list),
  643.              row,
  644.              1,
  645.              bzp->name,
  646.              2,
  647.              pwidget->paths_pixmap,
  648.              NULL);
  649.  
  650.   gtk_clist_set_row_data_full (GTK_CLIST (paths_dialog->paths_list),
  651.                    row,
  652.                    (gpointer) pwidget,
  653.                    clear_pathwidget);
  654.  
  655.   gtk_signal_handler_block (GTK_OBJECT (paths_dialog->paths_list),
  656.                 paths_dialog->selsigid);
  657.   gtk_clist_select_row (GTK_CLIST (paths_dialog->paths_list),
  658.             paths_dialog->current_path_list->last_selected_row,
  659.             1);
  660.   gtk_signal_handler_unblock (GTK_OBJECT (paths_dialog->paths_list),
  661.                   paths_dialog->selsigid);
  662.  
  663.   pwidget->bzp = bzp;
  664. }
  665.  
  666. static void
  667. paths_dialog_preview_extents (void)
  668. {
  669.   GimpImage *gimage;
  670.  
  671.   if (!paths_dialog)
  672.     return;
  673.  
  674.  if (! (gimage = paths_dialog->gimage))
  675.     return;
  676.  
  677.   paths_dialog->gimage_width  = gimage->width;
  678.   paths_dialog->gimage_height = gimage->height;
  679.  
  680.   /*  Get the image width and height variables, based on the gimage  */
  681.   if (gimage->width > gimage->height)
  682.     paths_dialog->ratio = (double) preview_size / (double) gimage->width;
  683.   else
  684.     paths_dialog->ratio = (double) preview_size / (double) gimage->height;
  685.  
  686.   if (preview_size)
  687.     {
  688.       paths_dialog->image_width = (int) (paths_dialog->ratio * gimage->width);
  689.       paths_dialog->image_height = (int) (paths_dialog->ratio * gimage->height);
  690.       if (paths_dialog->image_width < 1) paths_dialog->image_width = 1;
  691.       if (paths_dialog->image_height < 1) paths_dialog->image_height = 1;
  692.     }
  693.   else
  694.     {
  695.       paths_dialog->image_width  = path_width;
  696.       paths_dialog->image_height = path_height;
  697.     }
  698. }
  699.  
  700. static void
  701. paths_select_row (GtkWidget      *widget, 
  702.           gint            row,
  703.           gint            column,
  704.           GdkEventButton *event,
  705.           gpointer        data)
  706. {
  707.   PathWidget *pwidget;
  708.   Path* bzp;
  709.   BezierSelect * bsel;
  710.   GDisplay *gdisp;
  711.   gint last_row;
  712.  
  713.   pwidget = (PathWidget *) gtk_clist_get_row_data (GTK_CLIST (widget), row);
  714.  
  715.   if (!pwidget ||
  716.       (paths_dialog->current_path_list->last_selected_row == row &&
  717.        paths_dialog->been_selected == TRUE))
  718.     {
  719.       if (column)
  720.     return;
  721.     }
  722.  
  723.   last_row = paths_dialog->current_path_list->last_selected_row;
  724.  
  725.   bzp = (Path*)g_slist_nth_data(paths_dialog->current_path_list->bz_paths,row);
  726.  
  727.   g_return_if_fail(bzp != NULL);
  728.  
  729.   if(column == 0)
  730.     {
  731.       if(bzp->locked == 0)
  732.     {
  733.       bzp->locked = 1;
  734.       if (paths_dialog->selected_row_num == row)
  735.         gtk_clist_set_pixmap (GTK_CLIST (paths_dialog->paths_list),
  736.                   row,
  737.                   0,
  738.                   paths_dialog->pixmap_locked_selected,
  739.                   NULL);
  740.       else
  741.         gtk_clist_set_pixmap (GTK_CLIST (paths_dialog->paths_list),
  742.                   row,
  743.                   0,
  744.                   paths_dialog->pixmap_locked_normal,
  745.                   NULL);
  746.           }
  747.       else
  748.     {
  749.       gint tmprow;
  750.  
  751.       bzp->locked = 0;
  752.       gtk_clist_set_text (GTK_CLIST (paths_dialog->paths_list),
  753.                   row,
  754.                   0,
  755.                   "");
  756.       /* There should be an easier way of updating the preview! */
  757.       bsel = path_to_beziersel (bzp);
  758.       tmprow = paths_dialog->current_path_list->last_selected_row;
  759.       paths_dialog->current_path_list->last_selected_row = row;
  760.       paths_update_preview (bsel);
  761.       bezier_select_free (bsel);
  762.       paths_dialog->current_path_list->last_selected_row = tmprow;
  763.       paths_dialog->selected_row_num = tmprow;
  764.     }
  765.  
  766.       /* Put hightlight back on the old original selection */
  767.       gtk_signal_handler_block (GTK_OBJECT (paths_dialog->paths_list),
  768.                 paths_dialog->selsigid);
  769.  
  770.       gtk_clist_select_row (GTK_CLIST (paths_dialog->paths_list),
  771.                 last_row,
  772.                 1);
  773.  
  774.       gtk_signal_handler_unblock (GTK_OBJECT (paths_dialog->paths_list),
  775.                   paths_dialog->selsigid);
  776.  
  777.       return;
  778.     }
  779.  
  780.   paths_dialog->selected_row_num = row;
  781.   paths_dialog->current_path_list->last_selected_row = row;
  782.   paths_dialog->been_selected = TRUE;
  783.  
  784.   if(bzp->locked)
  785.     gtk_clist_set_pixmap (GTK_CLIST (paths_dialog->paths_list),
  786.               row,
  787.               0,
  788.               paths_dialog->pixmap_locked_selected,
  789.               NULL);
  790.  
  791.   bsel = path_to_beziersel (bzp);
  792.   gdisp = gdisplays_check_valid (paths_dialog->current_path_list->gdisp,
  793.                  paths_dialog->gimage);
  794.   if (!gdisp)
  795.     {
  796.       /*g_warning("Lost image which bezier curve belonged to");*/
  797.       return;
  798.     }
  799.   bezier_paste_bezierselect_to_current (gdisp, bsel);
  800.   paths_update_preview (bsel);
  801.   bezier_select_free (bsel);
  802. }
  803.  
  804. static void
  805. paths_unselect_row (GtkWidget      *widget, 
  806.             gint            row,
  807.             gint            column,
  808.             GdkEventButton *event,
  809.             gpointer        data)
  810. {
  811.   PathWidget *pwidget;
  812.   Path* bzp;
  813.  
  814.   pwidget = (PathWidget *) gtk_clist_get_row_data (GTK_CLIST (widget), row);
  815.  
  816.   if (!pwidget)
  817.     return;
  818.  
  819.   bzp = pwidget->bzp;
  820.  
  821.   g_return_if_fail (bzp != NULL);
  822.  
  823.   if (column && bzp->locked)
  824.     {
  825.       gtk_clist_set_pixmap (GTK_CLIST (paths_dialog->paths_list),
  826.                 row,
  827.                 0,
  828.                 paths_dialog->pixmap_locked_normal,
  829.                 NULL);
  830.     }
  831. }
  832.  
  833. void
  834. paths_dialog_update (GimpImage* gimage)
  835. {
  836.   PathList* new_path_list;
  837.   GSList *plist;
  838.   gint loop;
  839.   gint tmprow;
  840.  
  841.   if (!paths_dialog || !gimage)
  842.     return;
  843.  
  844.   if (paths_dialog->gimage == gimage &&
  845.       paths_dialog->current_path_list ==
  846.       (PathList*) gimp_image_get_paths (gimage))
  847.     return;
  848.  
  849.   paths_dialog->gimage = gimage;
  850.  
  851.   paths_dialog_preview_extents ();
  852.  
  853.   /*  clear clist out  */
  854.   gtk_clist_freeze (GTK_CLIST (paths_dialog->paths_list));
  855.   gtk_clist_clear (GTK_CLIST (paths_dialog->paths_list));
  856.   gtk_clist_thaw (GTK_CLIST (paths_dialog->paths_list));
  857.  
  858.   /*  Find bz list  */
  859.   new_path_list = (PathList*) gimp_image_get_paths (gimage);
  860.  
  861.   paths_dialog->current_path_list = new_path_list;
  862.   paths_dialog->been_selected = FALSE;
  863.  
  864.   paths_dialog_set_menu_sensitivity ();
  865.  
  866.   paths_dialog_set_default_op ();
  867.  
  868.   if (!new_path_list)
  869.     return;
  870.  
  871.   /* update the clist to reflect this images bz list */
  872.   /* go around the image list populating the clist */
  873.  
  874.   if (gimage != new_path_list->gimage)
  875.     {
  876.       g_warning("paths list: internal list error");
  877.     }
  878.  
  879.   plist = new_path_list->bz_paths;
  880.   loop = 0;
  881.  
  882.   tmprow = paths_dialog->current_path_list->last_selected_row;
  883.   while (plist)
  884.     {
  885.       paths_update_paths (plist->data,loop);
  886.       loop++;
  887.       plist = g_slist_next (plist);
  888.     }
  889.   paths_dialog->current_path_list->last_selected_row = tmprow;
  890.   paths_dialog->selected_row_num = tmprow;
  891.  
  892.   /* select last one */
  893.  
  894.   gtk_signal_handler_block (GTK_OBJECT (paths_dialog->paths_list),
  895.                 paths_dialog->selsigid);
  896.   gtk_clist_select_row (GTK_CLIST (paths_dialog->paths_list),
  897.             paths_dialog->current_path_list->last_selected_row,
  898.             1);
  899.   gtk_signal_handler_unblock (GTK_OBJECT (paths_dialog->paths_list),
  900.                   paths_dialog->selsigid);
  901.  
  902.   gtk_clist_moveto (GTK_CLIST (paths_dialog->paths_list),
  903.             paths_dialog->current_path_list->last_selected_row,
  904.             0,
  905.             0.5,
  906.             0.0);
  907. }
  908.  
  909. static void
  910. paths_update_paths (gpointer data,
  911.             gint     row)
  912. {
  913.   Path* bzp;
  914.   BezierSelect *bezier_sel;
  915.  
  916.   paths_add_path ((bzp = (Path*) data), -1);
  917.   /* Now fudge the drawing....*/
  918.   bezier_sel = path_to_beziersel (bzp);
  919.   paths_dialog->current_path_list->last_selected_row = row;
  920.   paths_update_preview (bezier_sel);
  921.   bezier_select_free (bezier_sel);
  922.  
  923.   if (bzp->locked)
  924.     {
  925.       if (paths_dialog->selected_row_num == row)
  926.     gtk_clist_set_pixmap (GTK_CLIST (paths_dialog->paths_list),
  927.                   row,
  928.                   0,
  929.                   paths_dialog->pixmap_locked_selected,
  930.                   NULL);
  931.       else
  932.     gtk_clist_set_pixmap (GTK_CLIST (paths_dialog->paths_list),
  933.                   row,
  934.                   0,
  935.                   paths_dialog->pixmap_locked_normal,
  936.                   NULL);
  937.     }
  938. }
  939.  
  940. static void
  941. do_rename_paths_callback (GtkWidget *widget, 
  942.               gchar     *text,
  943.               gpointer   data)
  944. {
  945.   GdkBitmap *mask;
  946.   guint8     spacing;
  947.   GdkPixmap *pixmap;
  948.  
  949.   if (!(GTK_CLIST (data)->selection))
  950.     return;
  951.  
  952.   gtk_clist_get_pixtext (GTK_CLIST (paths_dialog->paths_list),
  953.              paths_dialog->selected_row_num,
  954.              1,
  955.              NULL,
  956.              &spacing,
  957.              &pixmap,
  958.              &mask);
  959.  
  960.   gtk_clist_set_pixtext (GTK_CLIST (data),
  961.              paths_dialog->selected_row_num,
  962.              1,
  963.              text,
  964.              spacing,
  965.              pixmap,
  966.              mask);
  967.  
  968.   bz_change_name_row_to (paths_dialog->selected_row_num, text);
  969. }
  970.  
  971. static void
  972. paths_dialog_edit_path_query (GtkWidget *widget)
  973. {
  974.   GtkWidget *qbox;
  975.   GdkBitmap *mask;
  976.   gchar *text;
  977.   gint   ret;
  978.  
  979.   /* Get the current name */
  980.   ret = gtk_clist_get_pixtext (GTK_CLIST (paths_dialog->paths_list),
  981.                    paths_dialog->selected_row_num,
  982.                    1,
  983.                    &text,
  984.                    NULL,
  985.                    NULL,
  986.                    &mask);
  987.  
  988.   qbox = gimp_query_string_box (_("Edit Path Attributes"),
  989.                 gimp_standard_help_func,
  990.                 "paths/dialogs/edit_path_attributes.html",
  991.                 _("Enter a new name for the path"),
  992.                 text,
  993.                 NULL, NULL,
  994.                 do_rename_paths_callback, widget);
  995.   gtk_widget_show (qbox);
  996. }
  997.  
  998. static gint
  999. paths_list_events (GtkWidget *widget,
  1000.            GdkEvent  *event)
  1001. {
  1002.   GdkEventButton *bevent;
  1003.   static gint     last_row = -1;
  1004.   gint            this_column;
  1005.  
  1006.   switch (event->type)
  1007.     {
  1008.     case GDK_BUTTON_PRESS:
  1009.       bevent = (GdkEventButton *) event;
  1010.       if (!gtk_clist_get_selection_info (GTK_CLIST (paths_dialog->paths_list),
  1011.                      bevent->x,
  1012.                      bevent->y,
  1013.                      &last_row, &this_column))
  1014.     last_row = -1;
  1015.       else if (paths_dialog->selected_row_num != last_row)
  1016.     last_row = -1;
  1017.  
  1018.       if (bevent->button == 3)
  1019.     gtk_menu_popup (GTK_MENU (paths_dialog->ops_menu), 
  1020.             NULL, NULL, NULL, NULL, bevent->button, bevent->time);
  1021.       break;
  1022.  
  1023.     case GDK_2BUTTON_PRESS:
  1024.       bevent = (GdkEventButton *) event;
  1025.  
  1026.       if (last_row != -1 && 
  1027.       gtk_clist_get_selection_info (GTK_CLIST (paths_dialog->paths_list),
  1028.                     bevent->x,
  1029.                     bevent->y,
  1030.                     NULL, &this_column))
  1031.     {
  1032.       if (this_column == 1)
  1033.         {
  1034.           paths_dialog_edit_path_query (widget);
  1035.           return TRUE;
  1036.         }
  1037.       else
  1038.         return FALSE;
  1039.     }
  1040.       else
  1041.     return FALSE;
  1042.       
  1043.     default:
  1044.       break;
  1045.     }
  1046.   return FALSE;
  1047. }
  1048.  
  1049. static PathList *
  1050. path_add_to_current (PathList  *pip,
  1051.              Path      *bzp,
  1052.              GimpImage *gimage,
  1053.              gint       pos)
  1054. {
  1055.   /* add bzp to current list */
  1056.   if (!pip)
  1057.     {
  1058.       /* This image does not have a list */
  1059.       pip = path_list_new (gimage, 0, NULL);
  1060.  
  1061.       /* add to gimage */
  1062.       gimp_image_set_paths (gimage, pip);
  1063.     }
  1064.  
  1065.   if (pos < 0)
  1066.     pip->bz_paths = g_slist_append (pip->bz_paths,bzp);
  1067.   else
  1068.     pip->bz_paths = g_slist_insert (pip->bz_paths,bzp,pos);
  1069.  
  1070.   return pip;
  1071. }
  1072.  
  1073. static Path*
  1074. paths_dialog_new_path (PathList  **plp,
  1075.                gpointer    points,
  1076.                GimpImage  *gimage,
  1077.                gint        pos)
  1078. {
  1079.   static gint nseed = 0;
  1080.   Path* bzp;
  1081.  
  1082.   bzp  = path_dialog_new (gimage, nseed++, points);
  1083.   *plp = path_add_to_current (*plp, bzp, gimage, pos);
  1084.  
  1085.   return (bzp);
  1086. }
  1087.  
  1088. void 
  1089. paths_dialog_new_path_callback (GtkWidget *widget, 
  1090.                 gpointer   data)
  1091. {
  1092.   BezierSelect * bsel;
  1093.   GDisplay *gdisp;
  1094.   Path* bzp;
  1095.  
  1096.   bzp = paths_dialog_new_path (&paths_dialog->current_path_list,
  1097.                    NULL,
  1098.                    paths_dialog->gimage,
  1099.                    paths_dialog->selected_row_num);
  1100.  
  1101.   paths_add_path (bzp, paths_dialog->selected_row_num);
  1102.  
  1103.   paths_dialog_set_menu_sensitivity ();
  1104.  
  1105.   paths_dialog_set_default_op ();
  1106.  
  1107.   /* Clear the path display out */
  1108.   bsel = path_to_beziersel (bzp);
  1109.   gdisp = gdisplays_check_valid (paths_dialog->current_path_list->gdisp,
  1110.                  paths_dialog->gimage);
  1111.   bezier_paste_bezierselect_to_current (gdisp, bsel);
  1112.   bezier_select_free (bsel);
  1113. }
  1114.  
  1115. void 
  1116. paths_dialog_delete_path_callback (GtkWidget *widget, 
  1117.                    gpointer   udata)
  1118. {
  1119.   Path* bzp;
  1120.   PathList* plp;
  1121.   gboolean new_sz;
  1122.   gint row = paths_dialog->selected_row_num;
  1123.   BezierSelect *bsel  = NULL;
  1124.   GDisplay     *gdisp = NULL;
  1125.  
  1126.   g_return_if_fail (paths_dialog->current_path_list != NULL);
  1127.  
  1128.   /* Get current selection... ignore if none */
  1129.   if (paths_dialog->selected_row_num < 0)
  1130.     return;
  1131.   
  1132.   /* Get bzpath structure & delete its content */
  1133.   plp = paths_dialog->current_path_list;
  1134.   bzp = (Path*) g_slist_nth_data (plp->bz_paths, row); 
  1135.  
  1136.   /* Remove from list */
  1137.   plp->bz_paths = g_slist_remove (plp->bz_paths, bzp);
  1138.   new_sz = (g_slist_length (plp->bz_paths) > 0);
  1139.   path_free (bzp);
  1140.  
  1141.   /* Remove from the clist ... */ 
  1142.   gtk_signal_handler_block_by_data (GTK_OBJECT (paths_dialog->paths_list), 
  1143.                     paths_dialog);
  1144.   gtk_clist_remove (GTK_CLIST (paths_dialog->paths_list), row);
  1145.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (paths_dialog->paths_list), 
  1146.                       paths_dialog);
  1147.  
  1148.   /* If now empty free everything up */
  1149.   if (!plp->bz_paths || g_slist_length (plp->bz_paths) == 0)
  1150.     {
  1151.       gtk_signal_disconnect (GTK_OBJECT (plp->gimage),
  1152.                  plp->sig_id);
  1153.  
  1154.       gimp_image_set_paths (plp->gimage, NULL);
  1155.       path_list_free (plp);
  1156.  
  1157.       /* Paste an empty BezierSelect to the current display to emulate an empty path list */
  1158.  
  1159.       bsel = g_new0 (BezierSelect, 1);
  1160.       bezier_select_reset (bsel);
  1161.       gdisp = gdisplays_check_valid (paths_dialog->current_path_list->gdisp,
  1162.                      paths_dialog->gimage);
  1163.  
  1164.       bezier_paste_bezierselect_to_current (gdisp, bsel);
  1165.       bezier_select_free (bsel);
  1166.  
  1167.       paths_dialog->current_path_list = NULL;
  1168.  
  1169.       paths_dialog_set_menu_sensitivity ();
  1170.     }
  1171.  
  1172.   if (!new_sz)
  1173.     paths_dialog_set_default_op ();
  1174. }
  1175.  
  1176. void 
  1177. paths_dialog_paste_path_callback (GtkWidget *widget, 
  1178.                   gpointer   data)
  1179. {
  1180.   Path* bzp;
  1181.   PathList* plp;
  1182.   PathPoint* pp;
  1183.   BezierSelect * bezier_sel;
  1184.   gint tmprow;
  1185.   GDisplay *gdisp;
  1186.  
  1187.   gint row = paths_dialog->selected_row_num;
  1188.  
  1189.   g_return_if_fail (paths_dialog->current_path_list != NULL);
  1190.  
  1191.   if (!copy_pp)
  1192.     return;
  1193.  
  1194.   /* Get current selection... ignore if none */
  1195.   if (paths_dialog->selected_row_num < 0)
  1196.     return;
  1197.   
  1198.   /* Get bzpath structure  */
  1199.   plp = paths_dialog->current_path_list;
  1200.   if (!plp)
  1201.     return;
  1202.  
  1203.   bzp = (Path*) g_slist_nth_data (plp->bz_paths, row); 
  1204.  
  1205.   if (bzp->path_details)
  1206.     {
  1207.       pp = bzp->path_details->data;
  1208.       pp->type = BEZIER_MOVE;
  1209.       bzp->path_details = g_slist_concat (copy_pp->path_details,
  1210.                       bzp->path_details);
  1211.     }
  1212.   else
  1213.     {
  1214.       bzp->closed = TRUE;
  1215.       bzp->path_details = copy_pp->path_details;
  1216.       bzp->state = copy_pp->state;
  1217.     }
  1218.  
  1219.   /* First point on new curve is a moveto */
  1220.   copy_pp->path_details = NULL;
  1221.   path_free (copy_pp);
  1222.   copy_pp = NULL;
  1223.  
  1224.   paths_dialog_set_menu_sensitivity ();
  1225.  
  1226.   /* Now fudge the drawing....*/
  1227.   bezier_sel = path_to_beziersel (bzp);
  1228.   tmprow = paths_dialog->current_path_list->last_selected_row;
  1229.   paths_dialog->current_path_list->last_selected_row = row;
  1230.   gdisp = gdisplays_check_valid (paths_dialog->current_path_list->gdisp,
  1231.                  paths_dialog->gimage);
  1232.   bezier_paste_bezierselect_to_current (gdisp, bezier_sel);
  1233.   paths_update_preview (bezier_sel);
  1234.   bezier_select_free (bezier_sel);
  1235.   paths_dialog->current_path_list->last_selected_row = tmprow;
  1236. }
  1237.  
  1238. void 
  1239. paths_dialog_copy_path_callback (GtkWidget *widget,
  1240.                  gpointer   data)
  1241. {
  1242.   Path* bzp;
  1243.   PathList* plp;
  1244.   gint row = paths_dialog->selected_row_num;
  1245.  
  1246.   g_return_if_fail (paths_dialog->current_path_list != NULL);
  1247.  
  1248.   /* Get current selection... ignore if none */
  1249.   if (paths_dialog->selected_row_num < 0)
  1250.     return;
  1251.   
  1252.   /* Get bzpath structure  */
  1253.   plp = paths_dialog->current_path_list;
  1254.   bzp = (Path*) g_slist_nth_data (plp->bz_paths, row);
  1255.  
  1256.   if (!bzp->path_details || g_slist_length (bzp->path_details) <= 5)
  1257.     return;
  1258.  
  1259.   /* And store in static array */
  1260.   copy_pp = path_copy (paths_dialog->gimage, bzp);
  1261.  
  1262.   /* All paths that are in the cut buffer must be closed */
  1263.   if (!copy_pp->closed)
  1264.     path_close (copy_pp);
  1265.  
  1266.   paths_dialog_set_menu_sensitivity ();
  1267. }
  1268.  
  1269. void 
  1270. paths_dialog_dup_path_callback (GtkWidget *widget, 
  1271.                 gpointer   data)
  1272. {
  1273.   Path* bzp;
  1274.   PathList* plp;
  1275.   BezierSelect * bezier_sel;
  1276.   gint row;
  1277.   gint tmprow;
  1278.  
  1279.   g_return_if_fail (paths_dialog->current_path_list != NULL);
  1280.  
  1281.   /* Get current selection... ignore if none */
  1282.   if (paths_dialog->selected_row_num < 0)
  1283.     return;
  1284.   
  1285.   row = paths_dialog->current_path_list->last_selected_row;
  1286.   /* Get bzpath structure  */
  1287.   plp = paths_dialog->current_path_list;
  1288.   bzp = (Path*) g_slist_nth_data (plp->bz_paths, row); 
  1289.  
  1290.   /* Insert at the current position */
  1291.   bzp = path_copy (paths_dialog->gimage, bzp);
  1292.   plp->bz_paths = g_slist_insert (plp->bz_paths, bzp, row);
  1293.   paths_add_path (bzp, row);
  1294.  
  1295.   /* Now fudge the drawing....*/
  1296.   bezier_sel = path_to_beziersel (bzp);
  1297.   tmprow = paths_dialog->current_path_list->last_selected_row;
  1298.   paths_dialog->current_path_list->last_selected_row = row;
  1299.   paths_update_preview (bezier_sel);
  1300.   bezier_select_free (bezier_sel);
  1301.   paths_dialog->current_path_list->last_selected_row = tmprow;
  1302. }
  1303.  
  1304. static void 
  1305. paths_dialog_advanced_to_path_callback (GtkWidget *widget, 
  1306.                     gpointer   data)
  1307. {
  1308.   ProcRecord *proc_rec;
  1309.   Argument   *args;
  1310.   GimpImage *gimage;
  1311.  
  1312.   /*  find the sel2path PDB record  */
  1313.   if ((proc_rec = procedural_db_lookup ("plug_in_sel2path_advanced")) == NULL)
  1314.     {
  1315.       g_message ("paths_dialog_adavanced_to_path_callback(): selection to path (advanced) procedure lookup failed");
  1316.       return;
  1317.     }
  1318.  
  1319.   gimage = paths_dialog->gimage;
  1320.  
  1321.   /*  plug-in arguments as if called by <Image>/Filters/...  */
  1322.   args = g_new (Argument, 3);
  1323.   args[0].arg_type = PDB_INT32;
  1324.   args[0].value.pdb_int = RUN_INTERACTIVE;
  1325.   args[1].arg_type = PDB_IMAGE;
  1326.   args[1].value.pdb_int = (gint32) pdb_image_to_id (gimage);
  1327.   args[2].arg_type = PDB_DRAWABLE;
  1328.   args[2].value.pdb_int = (gint32) (gimage_active_drawable (gimage))->ID;
  1329.  
  1330.   plug_in_run (proc_rec, args, 3, FALSE, TRUE,
  1331.            (gimage_active_drawable (gimage))->ID);
  1332.  
  1333.   g_free (args);
  1334.  
  1335. }
  1336.  
  1337. static void 
  1338. paths_dialog_null_callback (GtkWidget *widget, 
  1339.                 gpointer   data)
  1340. {
  1341.   /* Maybe some more here later? */
  1342. }
  1343.  
  1344. void 
  1345. paths_dialog_sel_to_path_callback (GtkWidget *widget, 
  1346.                    gpointer   data)
  1347. {
  1348.   ProcRecord *proc_rec;
  1349.   Argument   *args;
  1350.   GimpImage  *gimage;
  1351.   GDisplay   *gdisp;
  1352.  
  1353.   /*  find the sel2path PDB record  */
  1354.   if ((proc_rec = procedural_db_lookup ("plug_in_sel2path")) == NULL)
  1355.     {
  1356.       g_message ("paths_dialog_sel_to_path_callback(): selection to path procedure lookup failed");
  1357.       return;
  1358.     }
  1359.  
  1360.   gimage = paths_dialog->gimage;
  1361.  
  1362.   /*  plug-in arguments as if called by <Image>/Filters/...  */
  1363.   args = g_new (Argument, 3);
  1364.   args[0].arg_type = PDB_INT32;
  1365.   args[0].value.pdb_int = RUN_INTERACTIVE;
  1366.   args[1].arg_type = PDB_IMAGE;
  1367.   args[1].value.pdb_int = (gint32) pdb_image_to_id (gimage);
  1368.   args[2].arg_type = PDB_DRAWABLE;
  1369.   args[2].value.pdb_int = (gint32) (gimage_active_drawable (gimage))->ID;
  1370.  
  1371.   /* get the display by asking the current context */
  1372.   gdisp = gimp_context_get_display (gimp_context_get_user ());
  1373.   plug_in_run (proc_rec, args, 3, FALSE, TRUE,
  1374.            gdisp? gdisp->ID : 0);
  1375.  
  1376.   g_free (args);
  1377. }
  1378.  
  1379.  
  1380. void 
  1381. paths_dialog_path_to_sel_callback (GtkWidget *widget, 
  1382.                    gpointer   data)
  1383. {
  1384.   Path* bzp;
  1385.   PathList* plp;
  1386.   BezierSelect * bezier_sel;
  1387.   GDisplay  * gdisp;
  1388.   gint row = paths_dialog->selected_row_num;
  1389.  
  1390.   g_return_if_fail (paths_dialog->current_path_list != NULL);
  1391.  
  1392.   /* Get current selection... ignore if none */
  1393.   if (paths_dialog->selected_row_num < 0)
  1394.     return;
  1395.   
  1396.   /* Get bzpath structure  */
  1397.   plp = paths_dialog->current_path_list;
  1398.   bzp = (Path*) g_slist_nth_data (plp->bz_paths, row); 
  1399.  
  1400.   /* Return if no point list */
  1401.   if (!bzp->path_details)
  1402.     return;
  1403.  
  1404.   /* Now do the selection....*/
  1405.   gdisp = gdisplays_check_valid (paths_dialog->current_path_list->gdisp,
  1406.                  paths_dialog->gimage);
  1407.  
  1408.   if (!bzp->closed)
  1409.     {
  1410.       Path* bzpcopy = path_copy (paths_dialog->gimage,bzp);
  1411.       /* Close it */
  1412.       path_close (bzpcopy);
  1413.       bezier_sel = path_to_beziersel (bzpcopy);
  1414.       path_free (bzpcopy);
  1415.       bezier_to_selection (bezier_sel, gdisp);
  1416.       bezier_select_free (bezier_sel);
  1417.  
  1418.       /* Force display to show no closed curve */
  1419.       bezier_sel = path_to_beziersel (bzp);
  1420.       bezier_paste_bezierselect_to_current (gdisp, bezier_sel);
  1421.       bezier_select_free (bezier_sel);
  1422.     }
  1423.   else
  1424.     {
  1425.       bezier_sel = path_to_beziersel (bzp);
  1426.       bezier_to_selection (bezier_sel, gdisp);
  1427.       bezier_select_free (bezier_sel);
  1428.     }
  1429. }
  1430.  
  1431. void 
  1432. paths_dialog_stroke_path_callback (GtkWidget *widget, 
  1433.                    gpointer   data)
  1434. {
  1435.   Path* bzp;
  1436.   PathList* plp;
  1437.   gint row = paths_dialog->selected_row_num;
  1438.  
  1439.   g_return_if_fail (paths_dialog->current_path_list != NULL);
  1440.  
  1441.   /* Get current selection... ignore if none */
  1442.   if (paths_dialog->selected_row_num < 0)
  1443.     return;
  1444.   
  1445.   /* Get bzpath structure  */
  1446.   plp = paths_dialog->current_path_list;
  1447.   bzp = (Path*) g_slist_nth_data (plp->bz_paths, row); 
  1448.  
  1449.   /* Now do the stroke....*/
  1450.   path_stroke (paths_dialog->gimage, paths_dialog->current_path_list, bzp);
  1451. }
  1452.  
  1453. void
  1454. paths_dialog_edit_path_attributes_callback (GtkWidget *widget,
  1455.                         gpointer   data)
  1456. {
  1457.   if (paths_dialog && paths_dialog->paths_list)
  1458.     paths_dialog_edit_path_query (paths_dialog->paths_list);
  1459. }
  1460.  
  1461. static void
  1462. paths_dialog_map_callback (GtkWidget *widget,
  1463.                gpointer   data)
  1464. {
  1465.   if (!paths_dialog)
  1466.     return;
  1467.  
  1468.   gtk_window_add_accel_group (GTK_WINDOW (lc_dialog->shell),
  1469.                   paths_dialog->accel_group);
  1470.  
  1471.   paths_dialog_preview_extents ();
  1472. }
  1473.  
  1474. static void
  1475. paths_dialog_unmap_callback (GtkWidget *widget,
  1476.                  gpointer   data)
  1477. {
  1478.   if (!paths_dialog)
  1479.     return;
  1480.   
  1481.   gtk_window_remove_accel_group (GTK_WINDOW (lc_dialog->shell),
  1482.                  paths_dialog->accel_group);
  1483. }
  1484.  
  1485. void
  1486. paths_dialog_destroy_cb (GtkObject *object,
  1487.              gpointer   data)
  1488. {
  1489.   GimpImage *gimage = (GimpImage *)object;
  1490.   PathList* new_path_list;
  1491.  
  1492.   if (!paths_dialog)
  1493.     return;
  1494.  
  1495.   if (paths_dialog->current_path_list && 
  1496.       gimage == paths_dialog->current_path_list->gimage)
  1497.     {
  1498.       /* showing could be last so remove here.. might get 
  1499.      done again if not the last one
  1500.       */
  1501.       paths_dialog->current_path_list = NULL;
  1502.       paths_dialog->been_selected = FALSE;
  1503.  
  1504.       gtk_clist_freeze (GTK_CLIST (paths_dialog->paths_list));
  1505.       gtk_clist_clear (GTK_CLIST (paths_dialog->paths_list));
  1506.       gtk_clist_thaw (GTK_CLIST (paths_dialog->paths_list));
  1507.     }
  1508.  
  1509.   /* Find bz list */  
  1510.   new_path_list = (PathList*) gimp_image_get_paths (gimage);
  1511.  
  1512.   if (!new_path_list)
  1513.     return; /* Already removed - signal handler just left in the air */
  1514.  
  1515.   path_list_free (new_path_list);
  1516.  
  1517.   gimp_image_set_paths (gimage, NULL);
  1518. }
  1519.  
  1520. /* Functions used from the bezier code .. tie in with this code */
  1521. static GSList *
  1522. pathpoints_create (BezierSelect *sel)
  1523. {
  1524.   gint i;
  1525.   GSList *list = NULL;
  1526.   PathPoint *pathpoint;
  1527.   BezierPoint *pts = (BezierPoint *) sel->points;
  1528.   BezierPoint *start_pnt = pts;
  1529.   gint need_move = 0;
  1530.  
  1531.   for (i=0; i< sel->num_points; i++)
  1532.     {
  1533.       pathpoint = path_point_new ((need_move)?BEZIER_MOVE:pts->type,
  1534.                   (gdouble)pts->x,(gdouble)pts->y);
  1535.       need_move = 0;
  1536.       list = g_slist_append (list, pathpoint);
  1537.       if(pts->next_curve)
  1538.     {
  1539.       /* The curve must loop back on itself */
  1540.       if(start_pnt != pts->next)
  1541.         g_warning("Curve of of sync");
  1542.       
  1543.       need_move = 1;
  1544.       pts = pts->next_curve;
  1545.       start_pnt = pts;
  1546.     }
  1547.       else
  1548.     {
  1549.       pts = pts->next;
  1550.     }
  1551.     }
  1552.   return (list);
  1553. }
  1554.  
  1555. GSList *
  1556. pathpoints_copy (GSList *list)
  1557. {
  1558.   GSList *slcopy = NULL;
  1559.   PathPoint* pdata;
  1560.   PathPoint* pathpoint;
  1561.   while(list)
  1562.     {
  1563.       pathpoint = g_new0(PathPoint,1);
  1564.       pdata = (PathPoint*)list->data;
  1565.       pathpoint->type = pdata->type;
  1566.       pathpoint->x = pdata->x;
  1567.       pathpoint->y = pdata->y;
  1568.       slcopy = g_slist_append(slcopy,pathpoint);
  1569.       list = g_slist_next(list);
  1570.     }
  1571.   return slcopy;
  1572. }
  1573.  
  1574. void
  1575. pathpoints_free (GSList *list)
  1576. {
  1577.   if (!list)
  1578.     return;
  1579.  
  1580.   g_slist_foreach (list, (GFunc)path_point_free, NULL);
  1581.   g_slist_free (list);
  1582. }
  1583.  
  1584. static void
  1585. paths_update_bzpath (PathList     *plp,
  1586.              BezierSelect *bezier_sel)
  1587. {
  1588.   Path* p;
  1589.  
  1590.   p = (Path*)g_slist_nth_data(plp->bz_paths,plp->last_selected_row);
  1591.   
  1592.   if(p->path_details) 
  1593.     pathpoints_free (p->path_details); 
  1594.   
  1595.   p->path_details = pathpoints_create(bezier_sel);
  1596.   p->closed = bezier_sel->closed;
  1597.   p->state  = bezier_sel->state;
  1598. }
  1599.  
  1600. static gboolean
  1601. paths_replaced_current (PathList     *plp,
  1602.             BezierSelect *bezier_sel)
  1603. {
  1604.   /* Is there a currently selected path in this image? */
  1605.   /* ALT if(paths_dialog && plp &&  */
  1606.   if(plp && 
  1607.      plp->last_selected_row >= 0)
  1608.     {  
  1609.       paths_update_bzpath(plp,bezier_sel);
  1610.       return TRUE;
  1611.     }
  1612.   return FALSE;
  1613. }
  1614.  
  1615. static gint 
  1616. number_curves_in_path (GSList *plist)
  1617. {
  1618.   gint count = 0;
  1619.   while(plist)
  1620.     {
  1621.       if(((PathPoint*)(plist->data))->type == BEZIER_MOVE &&
  1622.      g_slist_next(plist))
  1623.     {
  1624.       count++;
  1625.     }
  1626.       plist = g_slist_next(plist);
  1627.     }  
  1628.   return count;
  1629. }
  1630.  
  1631. static void 
  1632. paths_draw_segment_points (BezierSelect *bezier_sel, 
  1633.                GdkPoint     *pnt, 
  1634.                int           npoints,
  1635.                gpointer      udata)
  1636. {
  1637.   /* 
  1638.    * hopefully the image points are already in image space co-ords.
  1639.    * so just scale by ratio factor and draw 'em
  1640.    */
  1641.   gint loop;
  1642.   gint pcount = 0;
  1643.   GdkPoint * copy_pnt = g_new(GdkPoint,npoints);
  1644.   GdkPoint * cur_pnt  = copy_pnt;
  1645.   GdkPoint * last_pnt  = NULL;
  1646.   PathWidget *pwidget;
  1647.   gint row;
  1648.   PathCounts *curve_count = (PathCounts *) udata;
  1649.  
  1650.   /* we could remove duplicate points here */
  1651.  
  1652.   for(loop = 0; loop < npoints; loop++)
  1653.     {
  1654.       /* The "2" is because we have a boarder */
  1655.       cur_pnt->x = 2+(int) (paths_dialog->ratio * pnt->x);
  1656.       cur_pnt->y = 2+(int) (paths_dialog->ratio * pnt->y);
  1657.       pnt++;
  1658.       if(last_pnt &&
  1659.      last_pnt->x == cur_pnt->x &&
  1660.      last_pnt->y == cur_pnt->y)
  1661.     {
  1662.       /* same as last ... don't need this one */
  1663.       continue;
  1664.     }
  1665.  
  1666. /*       printf("converting %d [%d,%d] => [%d,%d]\n", */
  1667. /*          pcount,(int)pnt->x,(int)pnt->y,(int)cur_pnt->x,(int)cur_pnt->y); */
  1668.       last_pnt = cur_pnt;
  1669.       pcount++;
  1670.       cur_pnt++;
  1671.     }
  1672.  
  1673.   row = paths_dialog->current_path_list->last_selected_row;
  1674.  
  1675.   pwidget = (PathWidget *)
  1676.     gtk_clist_get_row_data (GTK_CLIST (paths_dialog->paths_list), row);
  1677.   
  1678.   if(pcount < 2)
  1679.     return;
  1680.  
  1681.   g_return_if_fail(pwidget != NULL);
  1682.  
  1683.   if(curve_count->c_count.count < curve_count->total_count || 
  1684.      bezier_sel->closed)
  1685.     paths_set_dash_line(paths_dialog->gc,FALSE);
  1686.   else
  1687.     paths_set_dash_line(paths_dialog->gc,TRUE);
  1688.   
  1689.   gdk_draw_lines (pwidget->paths_pixmap,
  1690.            paths_dialog->gc, copy_pnt, pcount);
  1691.  
  1692.   g_free(copy_pnt);
  1693. }
  1694.  
  1695. static void
  1696. paths_update_preview (BezierSelect *bezier_sel)
  1697. {
  1698.   gint row;
  1699.   PathCounts curve_count;
  1700.  
  1701.   if(paths_dialog &&
  1702.      paths_dialog->current_path_list &&
  1703.      (row = paths_dialog->current_path_list->last_selected_row) >= 0 &&
  1704.      preview_size)
  1705.     {
  1706.       PathWidget *pwidget;
  1707.  
  1708.       pwidget = (PathWidget *)
  1709.     gtk_clist_get_row_data (GTK_CLIST (paths_dialog->paths_list), row);
  1710.  
  1711.       /* Clear pixmap */
  1712.       clear_pixmap_preview (pwidget);
  1713.  
  1714.       curve_count.total_count =
  1715.     number_curves_in_path (pwidget->bzp->path_details);
  1716.  
  1717.       /* update .. */
  1718.       bezier_draw_curve (bezier_sel, paths_draw_segment_points,
  1719.              IMAGE_COORDS, &curve_count);
  1720.  
  1721.       /* update the pixmap */
  1722.       gtk_clist_set_pixtext (GTK_CLIST (paths_dialog->paths_list),
  1723.                  row,
  1724.                  1,
  1725.                  pwidget->bzp->name,
  1726.                  2,
  1727.                  pwidget->paths_pixmap,
  1728.                  NULL);
  1729.     }
  1730. }
  1731.  
  1732. static void 
  1733. paths_dialog_new_point_callback (GtkWidget *widget, 
  1734.                  gpointer   udata)
  1735. {
  1736.   bezier_select_mode (EXTEND_NEW);
  1737. }
  1738.  
  1739. static void 
  1740. paths_dialog_add_point_callback (GtkWidget *widget, 
  1741.                  gpointer   udata)
  1742. {
  1743.   bezier_select_mode (EXTEND_ADD);
  1744. }
  1745.  
  1746. static void 
  1747. paths_dialog_delete_point_callback (GtkWidget *widget, 
  1748.                     gpointer   udata)
  1749. {
  1750.   bezier_select_mode (EXTEND_REMOVE);
  1751. }
  1752.  
  1753. static void 
  1754. paths_dialog_edit_point_callback (GtkWidget *widget, 
  1755.                   gpointer   udata)
  1756. {
  1757.   bezier_select_mode (EXTEND_EDIT);
  1758. }
  1759.  
  1760. void
  1761. paths_dialog_flush (void)
  1762. {
  1763.   GimpImage *gimage;
  1764.  
  1765.   if (!paths_dialog)
  1766.     return;
  1767.  
  1768.  if (!(gimage = paths_dialog->gimage))
  1769.     return;
  1770.  
  1771.   gimage = paths_dialog->gimage;
  1772.  
  1773.   /* Check current_path_list since we might not have a valid preview.
  1774.    * which means it should be removed.. Or if we have one
  1775.    * created it!
  1776.    */
  1777.   if ((paths_dialog->current_path_list == NULL) ||
  1778.       (gimage->width != paths_dialog->gimage_width) ||
  1779.       (gimage->height != paths_dialog->gimage_height))
  1780.     {
  1781.       paths_dialog->gimage = NULL;
  1782.       paths_dialog_update (gimage);
  1783.     }
  1784. }
  1785.  
  1786. void 
  1787. paths_first_button_press (BezierSelect *bezier_sel,
  1788.               GDisplay     *gdisp)
  1789. {
  1790.   /* First time a button is pressed in this display */
  1791.   /* We have two choices here 
  1792.      Either:-
  1793.      1) We already have a paths item in the list. 
  1794.         => In this case the new one replaces the current entry. We
  1795.     need a callback into the bezier code to free things up.
  1796.      2) We don't have an entry. 
  1797.         => Create a new one and add this curve.
  1798.  
  1799.      In either case we need to update the preview widget..
  1800.  
  1801.      All this of course depends on the fact that gdisp is the same
  1802.      as before. 
  1803.   */
  1804.   Path* bzp; 
  1805.   PathList* plp;
  1806.  
  1807.   if(paths_dialog)
  1808.     {
  1809.       paths_dialog->been_selected = FALSE;
  1810.       /*ALT return;*/
  1811.     }
  1812.  
  1813.   /* Button not pressed in this image...
  1814.    * find which one it was pressed in if any.
  1815.    */
  1816.   plp = (PathList*)gimp_image_get_paths(gdisp->gimage);      
  1817.  
  1818.   /* Since beziers are part of the save format.. make the image dirty */
  1819. /*   undo_push_cantundo(gdisp->gimage, _("path modification")); */
  1820.   
  1821.   if(!paths_replaced_current(plp,bezier_sel))
  1822.     {
  1823.       bzp = paths_dialog_new_path (&plp, pathpoints_create(bezier_sel),gdisp->gimage,-1);
  1824.       bzp->closed = bezier_sel->closed;
  1825.       bzp->state  = bezier_sel->state;
  1826.       if(paths_dialog && paths_dialog->gimage == gdisp->gimage)
  1827.     {
  1828.       paths_dialog->current_path_list = plp;
  1829.       paths_add_path(bzp,-1);
  1830.     }
  1831.     }
  1832. }
  1833.  
  1834. void
  1835. paths_newpoint_current (BezierSelect *bezier_sel,
  1836.             GDisplay     *gdisp)
  1837. {
  1838.   /*  Check if currently showing the paths we are updating  */
  1839.   if (paths_dialog &&
  1840.       gdisp->gimage == paths_dialog->gimage)
  1841.     {
  1842.       paths_dialog_set_menu_sensitivity ();
  1843.  
  1844.       paths_update_preview (bezier_sel);
  1845.     }
  1846.  
  1847.   paths_first_button_press (bezier_sel, gdisp);
  1848. }
  1849.  
  1850. void 
  1851. paths_new_bezier_select_tool (void)
  1852. {
  1853.   if (paths_dialog)
  1854.     paths_dialog->been_selected = FALSE;
  1855. }
  1856.  
  1857.  
  1858. /**************************************************************/
  1859. /* Code to save/load from filesystem                          */
  1860. /**************************************************************/
  1861.  
  1862. static GtkWidget *file_dlg = 0;
  1863. static int load_store;
  1864.  
  1865. static void
  1866. path_write_current_to_file (FILE  *f,
  1867.                 Path*  bzp)
  1868. {
  1869.   GSList *list = bzp->path_details;
  1870.   PathPoint* pdata;
  1871.  
  1872.   fprintf(f, "Name: %s\n", bzp->name);
  1873.   fprintf(f, "#POINTS: %d\n", g_slist_length(bzp->path_details));
  1874.   fprintf(f, "CLOSED: %d\n", bzp->closed==1?1:0);
  1875.   fprintf(f, "DRAW: %d\n", 0);
  1876.   fprintf(f, "STATE: %d\n", bzp->state);
  1877.  
  1878.   while (list)
  1879.     {
  1880.       pdata = (PathPoint*)list->data;
  1881.       fprintf(f,"TYPE: %d X: %d Y: %d\n", pdata->type, (gint)pdata->x, (gint)pdata->y);
  1882.       list = g_slist_next(list);
  1883.     }
  1884. }
  1885.  
  1886. static void
  1887. file_ok_callback (GtkWidget *widget,
  1888.           gpointer   client_data) 
  1889. {
  1890.   GtkFileSelection *fs;
  1891.   FILE *f; 
  1892.   char* filename;
  1893.   Path* bzpath;
  1894.   PathList* plp;
  1895.   gint row = paths_dialog->selected_row_num;
  1896.   gint this_path_count = 0;
  1897.  
  1898.   fs = GTK_FILE_SELECTION (file_dlg);
  1899.   filename = gtk_file_selection_get_filename (fs);
  1900.  
  1901.   if (load_store) 
  1902.     {
  1903.       f = fopen(filename, "rb");
  1904.  
  1905.       if(!f)
  1906.     {
  1907.       g_message(_("Unable to open file %s"),filename);
  1908.       return;
  1909.     }
  1910.       
  1911.       while(!feof(f))
  1912.     {
  1913.       GSList * pts_list = NULL;
  1914.       gchar *txt = g_new(gchar,512);
  1915.       gchar *txtstart = txt;
  1916.       gint readfields = 0;
  1917.       int val, type, closed, i, draw, state;
  1918.       double x,y;
  1919.  
  1920.       if(!fgets(txt,512,f) || strlen(txt) < 7)
  1921.         {
  1922.           g_message(_("Failed to read from %s"),filename);
  1923.           gtk_widget_hide (file_dlg);  
  1924.           return;
  1925.         }
  1926.  
  1927.       txt += 6; /* Miss out 'Name: ' bit */
  1928.       txt[strlen(txt)-1] = '\0';
  1929.  
  1930.       readfields += fscanf(f, "#POINTS: %d\n", &val);
  1931.        readfields += fscanf(f, "CLOSED: %d\n", &closed);
  1932.       readfields += fscanf(f, "DRAW: %d\n", &draw);
  1933.       readfields += fscanf(f, "STATE: %d\n", &state);
  1934.  
  1935.       if(readfields != 4)
  1936.         {
  1937.           g_message(_("Failed to read path from %s"),filename);
  1938.           gtk_widget_hide (file_dlg);  
  1939.           return;
  1940.         }
  1941.  
  1942.       if(val <= 0)
  1943.         {
  1944.           g_message(_("No points specified in path file %s"),filename);
  1945.           gtk_widget_hide (file_dlg);  
  1946.           return;
  1947.         }
  1948.  
  1949.       for(i=0; i< val; i++)
  1950.         {
  1951.           PathPoint* bpt;
  1952.           readfields = fscanf(f,"TYPE: %d X: %lg Y: %lg\n", &type, &x, &y);
  1953.           if(readfields != 3)
  1954.         {
  1955.           g_message(_("Failed to read path points from %s"),filename);
  1956.           gtk_widget_hide (file_dlg);  
  1957.           return;
  1958.         }
  1959.           this_path_count++;
  1960.           switch(type)
  1961.         {
  1962.         case BEZIER_ANCHOR:
  1963.         case BEZIER_CONTROL:
  1964.           break;
  1965.         case BEZIER_MOVE:
  1966.           if(this_path_count < 6)
  1967.             {
  1968.               g_warning("Invalid single point in path\n");
  1969.               gtk_widget_hide (file_dlg);  
  1970.               return;
  1971.             }
  1972.           this_path_count = 0;
  1973.           break;
  1974.         default:
  1975.           g_warning("Invalid point type passed\n");
  1976.           gtk_widget_hide (file_dlg);  
  1977.           return;
  1978.         }
  1979.  
  1980.           bpt = path_point_new (type, (gdouble)x, (gdouble)y);
  1981.           pts_list = g_slist_append(pts_list,bpt);
  1982.         }
  1983.  
  1984.       bzpath = path_new(paths_dialog->gimage,
  1985.                 BEZIER,
  1986.                 pts_list,
  1987.                 closed,
  1988.                 state,
  1989.                 0, /* Can't be locked */
  1990.                 0, /* No tattoo assigned */
  1991.                 txt);
  1992.       
  1993.       g_free(txtstart);
  1994.  
  1995.       paths_dialog->current_path_list = 
  1996.         path_add_to_current(paths_dialog->current_path_list,
  1997.                   bzpath,
  1998.                   paths_dialog->gimage,
  1999.                   row);
  2000.       paths_add_path (bzpath, row);
  2001.  
  2002.       gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list),
  2003.                    paths_dialog->current_path_list->last_selected_row,
  2004.                    1);
  2005.  
  2006.       paths_dialog_set_menu_sensitivity ();
  2007.  
  2008.       if (!val)
  2009.         paths_dialog_set_default_op ();
  2010.     }
  2011.       fclose (f);
  2012.     } 
  2013.   else 
  2014.     {
  2015.       Path* bzp;
  2016.  
  2017.       /* Get current selection... ignore if none */
  2018.       if(paths_dialog->selected_row_num < 0)
  2019.     return;
  2020.       
  2021.       /* Get bzpath structure  */
  2022.       plp = paths_dialog->current_path_list;
  2023.       bzp = (Path*)g_slist_nth_data(plp->bz_paths,row); 
  2024.  
  2025.       f = fopen(filename, "wb");
  2026.       if (NULL == f) 
  2027.     {
  2028.       g_message (_("open failed on %s: %s\n"), filename, g_strerror(errno));
  2029.       return;
  2030.     }
  2031.  
  2032.       /* Write the current selection out. */
  2033.       path_write_current_to_file (f,bzp);
  2034.  
  2035.       fclose (f);
  2036.     }
  2037.   gtk_widget_hide (file_dlg);  
  2038. }
  2039.  
  2040. static void
  2041. file_cancel_callback (GtkWidget *widget,
  2042.               gpointer   data) 
  2043. {
  2044.   gtk_widget_hide (file_dlg);
  2045. }
  2046.  
  2047. static void
  2048. make_file_dlg (gpointer data) 
  2049. {
  2050.   file_dlg = gtk_file_selection_new (_("Load/Store Bezier Curves"));
  2051.   gtk_window_set_wmclass (GTK_WINDOW (file_dlg), "load_save_path", "Gimp");
  2052.   gtk_window_set_position (GTK_WINDOW (file_dlg), GTK_WIN_POS_MOUSE);
  2053.  
  2054.   gtk_container_set_border_width (GTK_CONTAINER (file_dlg), 2);
  2055.   gtk_container_set_border_width (GTK_CONTAINER (GTK_FILE_SELECTION (file_dlg)->button_area), 2);
  2056.  
  2057.   gtk_signal_connect
  2058.     (GTK_OBJECT (GTK_FILE_SELECTION (file_dlg)->cancel_button), "clicked",
  2059.      GTK_SIGNAL_FUNC (file_cancel_callback),
  2060.      data);
  2061.   gtk_signal_connect
  2062.     (GTK_OBJECT (GTK_FILE_SELECTION (file_dlg)->ok_button), "clicked",
  2063.      GTK_SIGNAL_FUNC (file_ok_callback),
  2064.      data);
  2065.   gtk_signal_connect (GTK_OBJECT (file_dlg), "delete_event",
  2066.               GTK_SIGNAL_FUNC (gtk_widget_hide),
  2067.               NULL);
  2068.  
  2069.   /*  Connect the "F1" help key  */
  2070.   gimp_help_connect_help_accel (file_dlg, gimp_standard_help_func, NULL);
  2071. }
  2072.  
  2073. void 
  2074. paths_dialog_import_path_callback (GtkWidget *widget,
  2075.                    gpointer   data)
  2076. {
  2077.   /* Read and add at current position */
  2078.   if (!file_dlg) 
  2079.     {
  2080.       make_file_dlg (NULL);
  2081.     } 
  2082.   else 
  2083.     {
  2084.       if (GTK_WIDGET_VISIBLE (file_dlg))
  2085.     return;
  2086.     }
  2087.  
  2088.   gimp_help_set_help_data (file_dlg, NULL, "paths/dialogs/import_path.html");
  2089.  
  2090.   gtk_window_set_title (GTK_WINDOW (file_dlg), _("Load Path"));
  2091.   load_store = 1;
  2092.   gtk_widget_show (file_dlg);
  2093. }
  2094.  
  2095. void 
  2096. paths_dialog_export_path_callback (GtkWidget *widget,
  2097.                    gpointer   data)
  2098. {
  2099.   /* Export the path to a file */
  2100.   if (!file_dlg) 
  2101.     {
  2102.       make_file_dlg (NULL);
  2103.     } 
  2104.   else 
  2105.     {
  2106.       if (GTK_WIDGET_VISIBLE (file_dlg))
  2107.     return;
  2108.     }
  2109.  
  2110.   gimp_help_set_help_data (file_dlg, NULL, "paths/dialogs/export_path.html");
  2111.  
  2112.   gtk_window_set_title (GTK_WINDOW (file_dlg), _("Store Path"));
  2113.   load_store = 0;
  2114.   gtk_widget_show (file_dlg);
  2115. }
  2116.  
  2117. /*************************************/
  2118. /* Function for transforming paths   */
  2119. /*************************************/
  2120.  
  2121. /* These functions are the undo functions for the paths
  2122.  * that have undergone transformations. 
  2123.  *
  2124.  * Generally speaking paths do not belong with the undo 
  2125.  * structures. However when a path undergoes a transformation 
  2126.  * then THIS path transformation should be part of the undo.
  2127.  * We do have a problem here since a point could have been
  2128.  * added to the path after the transformation. This 
  2129.  * point will be lost if the undo stuff is performed. It would 
  2130.  * then appear that this point is part of the undo structure.
  2131.  * I think it is fair that this happens since the user is telling
  2132.  * us to restore the state before the transformation took place.
  2133.  * Note tattoos are used to find which paths have been stored in the
  2134.  * undo buffer. So deleted paths will not suddenly reappear. (I did say
  2135.  * generally paths are not part of the undo structures).
  2136.  */
  2137. PathUndo *
  2138. path_transform_start_undo (GimpImage *gimage)
  2139. {
  2140.   /* Save only the locked paths away */
  2141.   PathList *plp;
  2142.   GSList   *plist;
  2143.   Path*     p;
  2144.   Path*     p_copy;
  2145.   GSList   *undo_list = NULL;
  2146.  
  2147.   /* Get bzpath structure  */
  2148.   plp = (PathList*) gimp_image_get_paths (gimage);
  2149.   
  2150.   if (!plp)
  2151.     return NULL;
  2152.   
  2153.   plist = plp->bz_paths;
  2154.  
  2155.   for (plist = plp->bz_paths; plist; plist = g_slist_next (plist))
  2156.     {
  2157.       p = (Path*)plist->data;
  2158.       if (p->locked)
  2159.     {
  2160.       /* save away for a rainy day */
  2161.       p_copy = path_copy (NULL, p); /* NULL means dont want new tattoo */
  2162.       undo_list = g_slist_append (undo_list, p_copy);
  2163.     }
  2164.     }
  2165.  
  2166.   return (PathUndo *) undo_list;
  2167. }
  2168.  
  2169. void
  2170. path_transform_free_undo (PathUndo *pundo)
  2171. {
  2172.   GSList *pundolist = (GSList*)pundo;
  2173.   Path   *p;
  2174.   /* free data associated with the transform path undo */
  2175.  
  2176.   while (pundolist)
  2177.     {
  2178.       p = (Path*)pundolist->data;
  2179.       path_free (p);
  2180.       pundolist = g_slist_next (pundolist);
  2181.     }
  2182.  
  2183.   g_slist_free (pundolist);
  2184. }
  2185.  
  2186. void
  2187. path_transform_do_undo (GimpImage *gimage,
  2188.             PathUndo  *pundo)
  2189. {
  2190.   GSList *pundolist;
  2191.   /* Restore the paths as they were before this transform took place. */
  2192.   Path *p_undo;
  2193.   Path *p;
  2194.   BezierSelect *bezier_sel;
  2195.   gint tmprow;
  2196.   gint loop;
  2197.   gboolean preview_update = FALSE;
  2198.   PathList *plp;
  2199.   GSList *plist;
  2200.  
  2201.   /* free data associated with the transform path undo */
  2202.  
  2203.   for (pundolist = pundo; pundolist; pundolist = g_slist_next(pundolist))
  2204.     {
  2205.       p_undo = (Path*)pundolist->data;
  2206.       /* Find the old path and replace it */
  2207.       p = path_get_path_by_tattoo (gimage, p_undo->tattoo);
  2208.       if (p)
  2209.     {
  2210.       /* Path is still around... undo the transform stuff */
  2211.       pathpoints_free (p->path_details);
  2212.       p->closed = p_undo->closed;
  2213.       p->state = p_undo->state;
  2214.       p->pathtype = p_undo->pathtype;
  2215.       p->path_details = pathpoints_copy (p_undo->path_details);
  2216.       preview_update = TRUE;
  2217.     }
  2218.     }
  2219.  
  2220.   if (preview_update && paths_dialog)
  2221.     {
  2222.       /* Heck the previews need updating...*/
  2223.       plp = (PathList *) gimp_image_get_paths (gimage);
  2224.       plist = plp->bz_paths;
  2225.       loop = 0;
  2226.       
  2227.       while (plist && 
  2228.          g_slist_length (plist) &&
  2229.          paths_dialog->current_path_list)
  2230.     {
  2231.       bezier_sel = path_to_beziersel (plist->data);
  2232.       tmprow = paths_dialog->current_path_list->last_selected_row;
  2233.       paths_dialog->current_path_list->last_selected_row = loop;
  2234.       paths_update_preview (bezier_sel);
  2235.       bezier_select_free (bezier_sel);
  2236.       paths_dialog->current_path_list->last_selected_row = tmprow;
  2237.       paths_dialog->selected_row_num = tmprow;
  2238.       loop++;
  2239.       plist = g_slist_next (plist);
  2240.     }
  2241.  
  2242.       /* Force selection .. it may have changed */
  2243.       if (bezier_tool_selected () && paths_dialog->current_path_list)
  2244.     {
  2245.       gtk_clist_select_row (GTK_CLIST (paths_dialog->paths_list),
  2246.                 paths_dialog->current_path_list->last_selected_row,
  2247.                 1);
  2248.     }
  2249.     }
  2250. }
  2251.  
  2252. static void
  2253. transform_func (GimpImage  *gimage, 
  2254.         int         flip, 
  2255.         gdouble     x, 
  2256.         gdouble     y)
  2257. {
  2258.   PathList      *plp;
  2259.   Path          *p;
  2260.   Path          *p_copy;
  2261.   GSList        *points_list;
  2262.   BezierSelect  *bezier_sel;
  2263.   GSList        *plist;
  2264.   gint           loop;
  2265.   gint           tmprow;
  2266.  
  2267.   /* As a first off lets just translate the current path */
  2268.  
  2269.   /* Get bzpath structure  */
  2270.   plp = (PathList *) gimp_image_get_paths (gimage);
  2271.  
  2272.   if (!plp)
  2273.     return;
  2274.  
  2275.   loop = 0;
  2276.   for (plist = plp->bz_paths; plist; plist = g_slist_next (plist))
  2277.     {
  2278.       p = (Path *) plist->data;
  2279.  
  2280.       if (p->locked)
  2281.     {
  2282.       p_copy = p;
  2283.       
  2284.       for (points_list = p_copy->path_details; points_list;
  2285.            points_list = g_slist_next (points_list))
  2286.         {
  2287.           PathPoint *ppoint = points_list->data;
  2288.  
  2289.           if (flip)
  2290.         {
  2291.           if (x > 0.0)
  2292.             {
  2293.               ppoint->y = gimage->height - ppoint->y;
  2294.             }
  2295.           else
  2296.             {
  2297.               ppoint->x = gimage->width - ppoint->x;
  2298.             }
  2299.         }
  2300.           else
  2301.         {
  2302.           ppoint->y += y;
  2303.           ppoint->x += x;
  2304.         }
  2305.         }
  2306.       
  2307.       /* Only update if we have a dialog, we have a currently 
  2308.        * selected path and its the showing the same image.
  2309.        */
  2310.  
  2311.       if(paths_dialog && 
  2312.          paths_dialog->current_path_list &&
  2313.          paths_dialog->gimage == gimage)
  2314.         {
  2315.           /* Now fudge the drawing....*/
  2316.           bezier_sel = path_to_beziersel(p_copy);
  2317.           tmprow = paths_dialog->current_path_list->last_selected_row;
  2318.           paths_dialog->current_path_list->last_selected_row = loop;
  2319.           paths_update_preview(bezier_sel);
  2320.           bezier_select_free(bezier_sel);
  2321.           paths_dialog->current_path_list->last_selected_row = tmprow;
  2322.           paths_dialog->selected_row_num = tmprow;
  2323.         }
  2324.     }
  2325.       loop++;
  2326.     }
  2327. }
  2328.  
  2329. void
  2330. path_transform_flip_horz (GimpImage  *gimage)
  2331. {
  2332.   transform_func (gimage, TRUE, 0.0, 0);
  2333. }
  2334.  
  2335. void
  2336. path_transform_flip_vert (GimpImage  *gimage)
  2337. {
  2338.   transform_func (gimage, TRUE, 1.0, 0);
  2339. }
  2340.  
  2341. void 
  2342. path_transform_xy (GimpImage *gimage,
  2343.             gint       x,
  2344.             gint       y)
  2345. {
  2346.   transform_func (gimage, FALSE, (gdouble) x, (gdouble) y);
  2347. }
  2348.  
  2349. void
  2350. path_transform_current_path (GimpImage   *gimage,
  2351.                  GimpMatrix3  transform,
  2352.                  gboolean     forpreview)
  2353. {
  2354.   PathList      *plp;
  2355.   Path          *p;
  2356.   Path          *p_copy;
  2357.   GSList        *points_list;
  2358.   BezierSelect  *bezier_sel;
  2359.   GSList        *plist;
  2360.   gint           loop;
  2361.   gint           tmprow;
  2362.  
  2363.   /* As a first off lets just translate the current path */
  2364.  
  2365.   /* Get bzpath structure  */
  2366.   plp = (PathList *) gimp_image_get_paths (gimage);
  2367.  
  2368.   if (!plp)
  2369.     return;
  2370.  
  2371.   loop = 0;
  2372.   for (plist = plp->bz_paths; plist; plist = g_slist_next (plist))
  2373.     {
  2374.       p = (Path *) plist->data;
  2375.  
  2376.       if (p->locked)
  2377.     {
  2378.       if (forpreview)
  2379.         p_copy = path_copy (NULL, p); /* NULL means dont want new tattoo */
  2380.       else
  2381.         p_copy = p;
  2382.  
  2383.       for (points_list = p_copy->path_details; points_list;
  2384.            points_list = g_slist_next (points_list))
  2385.         {
  2386.           gdouble newx,newy;
  2387.           PathPoint *ppoint = points_list->data;
  2388.  
  2389.           /*       printf("[x,y] = [%g,%g]\n",ppoint->x, ppoint->y); */
  2390.  
  2391.           gimp_matrix3_transform_point (transform,
  2392.                         ppoint->x,
  2393.                         ppoint->y,
  2394.                         &newx,&newy);
  2395.  
  2396.           /*       printf("->[x,y] = [%g,%g]\n", newx, newy); */
  2397.  
  2398.           ppoint->x = newx;
  2399.           ppoint->y = newy;
  2400.         }
  2401.       
  2402.       /* Only update if we have a dialog, we have a currently 
  2403.        * selected path and its the showing the same image.
  2404.        */
  2405.  
  2406.       if (paths_dialog && 
  2407.           paths_dialog->current_path_list &&
  2408.           paths_dialog->gimage == gimage)
  2409.         {
  2410.           /* Now fudge the drawing....*/
  2411.           bezier_sel = path_to_beziersel (p_copy);
  2412.           tmprow = paths_dialog->current_path_list->last_selected_row;
  2413.           paths_dialog->current_path_list->last_selected_row = loop;
  2414.           paths_update_preview (bezier_sel);
  2415.           bezier_select_free (bezier_sel);
  2416.           paths_dialog->current_path_list->last_selected_row = tmprow;
  2417.           paths_dialog->selected_row_num = tmprow;
  2418.         }
  2419.  
  2420.       if (forpreview)
  2421.         path_free (p_copy);
  2422.     }
  2423.       loop++;
  2424.     }
  2425. }
  2426.  
  2427. void
  2428. path_transform_draw_current (GDisplay    *gdisp, 
  2429.                  DrawCore    *core,
  2430.                  GimpMatrix3  transform)
  2431. {
  2432.   PathList     *plp;
  2433.   Path         *bzp;
  2434.   BezierSelect *bezier_sel;
  2435.   Path         *p_copy;
  2436.   GSList       *points_list;
  2437.   GSList       *plist;
  2438.  
  2439.   /* Get bzpath structure  */
  2440.   plp = (PathList *) gimp_image_get_paths (gdisp->gimage);
  2441.  
  2442.   if (!plp)
  2443.     return;
  2444.  
  2445.   for (plist = plp->bz_paths; plist; plist = g_slist_next (plist))
  2446.     {
  2447.       bzp = (Path *) plist->data;
  2448.       /* This image path is locked */
  2449.       if (bzp->locked)
  2450.     {
  2451.       p_copy = path_copy (NULL, bzp); /* NULL means dont want new tattoo */
  2452.       
  2453.       for (points_list = p_copy->path_details; points_list;
  2454.            points_list = g_slist_next (points_list))
  2455.         {
  2456.           gdouble newx,newy;
  2457.           PathPoint *ppoint = points_list->data;
  2458.  
  2459.           /*       printf("[x,y] = [%g,%g]\n",ppoint->x, ppoint->y); */
  2460.  
  2461.           gimp_matrix3_transform_point (transform,
  2462.                         ppoint->x,
  2463.                         ppoint->y,
  2464.                         &newx,&newy);
  2465.  
  2466.           /*       printf("->[x,y] = [%g,%g]\n", newx, newy); */
  2467.  
  2468.           ppoint->x = newx;
  2469.           ppoint->y = newy;
  2470.         }
  2471.  
  2472.       bezier_sel = path_to_beziersel (p_copy);
  2473.       bezier_sel->core = core; /* A bit hacky */
  2474.       bezier_draw (gdisp, bezier_sel);
  2475.       bezier_select_free (bezier_sel);
  2476.       path_free (p_copy);
  2477.     }
  2478.     }
  2479. }
  2480.  
  2481.  
  2482. /*************************************/
  2483. /* PDB function aids                 */
  2484. /*************************************/
  2485.  
  2486. /* Return TRUE if setting the path worked, else false */
  2487.  
  2488. gboolean
  2489. path_set_path (GimpImage *gimage,
  2490.            gchar     *pname)
  2491. {
  2492.   gint      row = 0;
  2493.   gboolean  found = FALSE;
  2494.   GSList   *tlist;
  2495.   PathList *plp;
  2496.  
  2497.   /* Get bzpath structure  */
  2498.   plp = (PathList *) gimp_image_get_paths (gimage);
  2499.  
  2500.   if(!plp)
  2501.     return FALSE;
  2502.  
  2503.   for (tlist = plp->bz_paths; tlist; tlist = g_slist_next (tlist))
  2504.     {
  2505.       gchar *test_str = ((Path*)(tlist->data))->name;
  2506.       if (strcmp (pname, test_str) == 0)
  2507.     {
  2508.       found = TRUE;
  2509.       break;
  2510.     }
  2511.       row++;
  2512.     }
  2513.  
  2514.   if(!found)
  2515.     return FALSE;
  2516.  
  2517.   if(paths_dialog)
  2518.     {
  2519.       gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list),
  2520.                row,
  2521.                1);
  2522.     }
  2523.   else
  2524.     {
  2525.       plp->last_selected_row = row;
  2526.     }
  2527.  
  2528.   return TRUE;
  2529. }
  2530.  
  2531. /* Set a path with the given set of points. */
  2532. /* We assume that there are enough points */
  2533. /* Return TRUE if path created OK. */
  2534.  
  2535. gboolean
  2536. path_set_path_points (GimpImage *gimage,
  2537.               gchar     *pname,
  2538.               gint       ptype,
  2539.               gint       pclosed,
  2540.               gint       num_pnts,
  2541.               gdouble   *pnts)
  2542. {
  2543.   PathList     *plist    = gimp_image_get_paths(gimage);
  2544.   GSList       *pts_list = NULL;
  2545.   Path         *bzpath;
  2546.   BezierSelect *bezier_sel;
  2547.   gint          pcount   = 0;
  2548.   gint          this_path_count = 0;
  2549.  
  2550.   if (num_pnts < 6 ||
  2551.       (pclosed && ((num_pnts/3) % 3)) ||
  2552.       (!pclosed && ((num_pnts/3) % 3) != 2))
  2553.     {
  2554.       g_warning ("wrong number of points\n");
  2555.       return FALSE;
  2556.     }
  2557.  
  2558.   if (ptype != BEZIER)
  2559.     ptype = BEZIER;
  2560.  
  2561.   while (num_pnts)
  2562.     {
  2563.       PathPoint *bpt;
  2564.       gint type;
  2565.       gdouble x; 
  2566.       gdouble y;
  2567.       
  2568. /*       if((pcount/2)%3) */
  2569. /*     type = BEZIER_CONTROL; */
  2570. /*       else */
  2571. /*     type = BEZIER_ANCHOR; */
  2572.  
  2573.       x = pnts[pcount++];
  2574.       y = pnts[pcount++];
  2575.       type = (gint)pnts[pcount++];
  2576.       this_path_count++;
  2577.  
  2578.       switch (type)
  2579.     {
  2580.     case BEZIER_ANCHOR:
  2581.     case BEZIER_CONTROL:
  2582.       break;
  2583.     case BEZIER_MOVE:
  2584.       if (this_path_count < 6)
  2585.         {
  2586.           g_warning ("Invalid single point in path\n");
  2587.           return FALSE;
  2588.         }
  2589.       this_path_count = 0;
  2590.       break;
  2591.     default:
  2592.       g_warning ("Invalid point type passed\n");
  2593.       return FALSE;
  2594.     }
  2595.  
  2596.       
  2597. /*       printf("New point type = %s, x = %d y= %d\n", */
  2598. /*          (type==BEZIER_CONTROL)?"CNTL":"ANCH", */
  2599. /*          (int)x, */
  2600. /*          (int)y); */
  2601.       
  2602.       bpt = path_point_new (type, (gdouble)x, (gdouble)y);
  2603.       pts_list = g_slist_append(pts_list,bpt);
  2604.  
  2605.       num_pnts -= 3;
  2606.     }
  2607.   
  2608.   bzpath = path_new (gimage,
  2609.              ptype,
  2610.              pts_list,
  2611.              pclosed,
  2612.              (pclosed) ? BEZIER_EDIT : BEZIER_ADD, /* state */
  2613.              0, /* Can't be locked */
  2614.              0, /* No tattoo assigned */
  2615.              pname);
  2616.  
  2617.   bezier_sel = path_to_beziersel(bzpath);
  2618.  
  2619.   /* Only add if paths dialog showing this window */
  2620.   if (paths_dialog && paths_dialog->gimage == gimage)
  2621.     { 
  2622.       paths_dialog->current_path_list =  
  2623.     path_add_to_current (paths_dialog->current_path_list, 
  2624.                  bzpath, 
  2625.                  paths_dialog->gimage, 
  2626.                  0); 
  2627.  
  2628.       paths_add_path (bzpath, 0); 
  2629.  
  2630.       /* Update the preview */
  2631.       paths_dialog->current_path_list->last_selected_row = 0;
  2632.       paths_update_preview (bezier_sel);
  2633.  
  2634.       gtk_clist_select_row (GTK_CLIST (paths_dialog->paths_list),
  2635.                 paths_dialog->current_path_list->last_selected_row,
  2636.                 1);
  2637.  
  2638.       paths_dialog_set_menu_sensitivity ();
  2639.     }
  2640.   else
  2641.     {
  2642.       GDisplay *gdisp;
  2643.  
  2644.       if (!plist)
  2645.     {
  2646.       /* If we haven't got a paths dialog */
  2647.       GSList *bzp_list = NULL;
  2648.  
  2649.       bzp_list = g_slist_append (bzp_list, bzpath);
  2650.       plist = path_list_new (gimage, 0, bzp_list);
  2651.       gimp_image_set_paths (gimage, plist);
  2652.     }
  2653.       else
  2654.     {
  2655.       path_add_to_current (plist, bzpath, gimage, 0);
  2656.     }
  2657.  
  2658.       /* This is a little HACK.. we need to find a display
  2659.        * to put the path image on.
  2660.        */
  2661.  
  2662.       gdisp = gdisplays_check_valid (NULL, gimage);
  2663.  
  2664.       /* Mark this path as selected */
  2665.       plist->last_selected_row = 0;
  2666.  
  2667.       /* Only paste if we have an image to paste to! */
  2668.       if (gdisp)
  2669.     bezier_paste_bezierselect_to_current (gdisp, bezier_sel);
  2670.     }
  2671.  
  2672.   bezier_select_free (bezier_sel);
  2673.  
  2674.   return TRUE;
  2675. }
  2676.  
  2677. gboolean
  2678. path_delete_path (GimpImage *gimage,
  2679.           gchar     *pname)
  2680. {
  2681.   gint      row = 0;
  2682.   gboolean  found = FALSE;
  2683.   GSList   *tlist;
  2684.   PathList *plp;
  2685.  
  2686.   if (!pname || !gimage)
  2687.     {
  2688.       g_warning ("paths_delete_path: invalid path");
  2689.       return FALSE;
  2690.     }
  2691.  
  2692.   /* Removed the named path ... */
  2693.   /* Get bzpath structure  */
  2694.   plp = (PathList *) gimp_image_get_paths (gimage);
  2695.  
  2696.   if(!plp)
  2697.     return FALSE;
  2698.  
  2699.   for (tlist = plp->bz_paths; tlist; tlist = g_slist_next (tlist))
  2700.     {
  2701.       gchar *test_str = ((Path *) (tlist->data))->name;
  2702.       if (strcmp (pname, test_str) == 0)
  2703.     {
  2704.       found = TRUE;
  2705.       break;
  2706.     }
  2707.       row++;
  2708.     }
  2709.  
  2710.   if (!found)
  2711.     return FALSE;
  2712.  
  2713.   plp->bz_paths = g_slist_remove (plp->bz_paths, tlist->data);
  2714.   /* If now empty free everything up */
  2715.   if (!plp->bz_paths || g_slist_length (plp->bz_paths) == 0)
  2716.     {
  2717.       gtk_signal_disconnect (GTK_OBJECT (plp->gimage), plp->sig_id);
  2718.       gimp_image_set_paths (plp->gimage, NULL);
  2719.       path_list_free (plp);
  2720.     }
  2721.  
  2722.   /* Redisplay if required */
  2723.   if (paths_dialog && paths_dialog->gimage == gimage)
  2724.     {
  2725.       paths_dialog->current_path_list = NULL;
  2726.       paths_dialog_flush ();
  2727.     }
  2728.  
  2729.   return TRUE;
  2730. }
  2731.