gfig.c 160 KB
Newer Older
Manish Singh's avatar
Manish Singh committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * This is a plug-in for the GIMP.
 *
 * Generates images containing vector type drawings.
 *
 * Copyright (C) 1997 Andy Thomas  alt@picnic.demon.co.uk
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
22
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Manish Singh's avatar
Manish Singh committed
23 24
 */

Tor Lillqvist's avatar
Tor Lillqvist committed
25 26
#include "config.h"

Manish Singh's avatar
Manish Singh committed
27 28
#include <stdio.h>
#include <stdlib.h>
29
#include <errno.h>
30

Tor Lillqvist's avatar
Tor Lillqvist committed
31
#ifdef HAVE_UNISTD_H
Manish Singh's avatar
Manish Singh committed
32
#include <unistd.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
33
#endif
34

Manish Singh's avatar
Manish Singh committed
35
#include <string.h>
36 37 38 39 40 41

#ifdef __GNUC__
#warning GTK_DISABLE_DEPRECATED
#endif
#undef GTK_DISABLE_DEPRECATED

Manish Singh's avatar
Manish Singh committed
42
#include <gtk/gtk.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
43

44
#ifdef G_OS_WIN32
Tor Lillqvist's avatar
Tor Lillqvist committed
45 46 47 48
#  include <io.h>
#  ifndef W_OK
#    define W_OK 2
#  endif
49 50
#endif

51 52
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
Manish Singh's avatar
Manish Singh committed
53

54 55
#include "libgimp/stdplugins-intl.h"

56 57 58 59 60 61 62 63 64
#include "gfig.h"
#include "gfig_arc.h"
#include "gfig_bezier.h"
#include "gfig_circle.h"
#include "gfig_ellipse.h"
#include "gfig_line.h"
#include "gfig_poly.h"
#include "gfig_spiral.h"
#include "gfig_star.h"
65 66
#include "gfig-stock.h"

67
#include "pix_data.h"
Manish Singh's avatar
Manish Singh committed
68

69

Manish Singh's avatar
Manish Singh committed
70 71
/***** Magic numbers *****/

72 73
#define PREVIEW_SIZE     400
#define SCALE_WIDTH      120
Manish Singh's avatar
Manish Singh committed
74

75 76 77 78
#define MIN_GRID         10
#define MAX_GRID         50
#define MAX_UNDO         10
#define MIN_UNDO         1
Manish Singh's avatar
Manish Singh committed
79 80
#define SMALL_PREVIEW_SZ 48
#define BRUSH_PREVIEW_SZ 32
81
#define GFIG_HEADER      "GFIG Version 0.1\n"
Manish Singh's avatar
Manish Singh committed
82

83 84 85 86 87 88 89
/* For the isometric grid */
#define SQRT3 1.73205080756887729353   /* Square root of 3 */
#define SIN_1o6PI_RAD 0.5              /* Sine    1/6 Pi Radians */
#define COS_1o6PI_RAD SQRT3 / 2        /* Cosine  1/6 Pi Radians */
#define TAN_1o6PI_RAD 1 / SQRT3        /* Tangent 1/6 Pi Radians == SIN / COS */
#define RECIP_TAN_1o6PI_RAD SQRT3      /* Reciprocal of Tangent 1/6 Pi Radians */

90
#define PREVIEW_MASK  (GDK_EXPOSURE_MASK       | \
Manish Singh's avatar
Manish Singh committed
91
		       GDK_POINTER_MOTION_MASK | \
92
                       GDK_BUTTON_PRESS_MASK   | \
Manish Singh's avatar
Manish Singh committed
93
		       GDK_BUTTON_RELEASE_MASK | \
94 95 96
		       GDK_BUTTON_MOTION_MASK  | \
		       GDK_KEY_PRESS_MASK      | \
		       GDK_KEY_RELEASE_MASK)
Manish Singh's avatar
Manish Singh committed
97

98
static GimpDrawable *gfig_select_drawable;
99 100
GtkWidget    *gfig_preview;
GtkWidget    *pic_preview;
101
static GtkWidget    *gfig_gtk_list;
102 103
gint32        gfig_image;
gint32        gfig_drawable;
104 105
static GtkWidget    *brush_page_pw;
static GtkWidget    *brush_sel_button;
Manish Singh's avatar
Manish Singh committed
106 107

static gint   tile_width, tile_height;
108
static gint   img_width, img_height, img_bpp, real_img_bpp;
Manish Singh's avatar
Manish Singh committed
109 110

static void      query  (void);
111 112 113 114 115
static void      run    (const gchar      *name,
			 gint              nparams,
			 const GimpParam  *param,
			 gint             *nreturn_vals,
			 GimpParam       **return_vals);
116 117 118 119 120 121 122 123 124 125

static gint      gfig_dialog               (void);
static void      gfig_ok_callback          (GtkWidget *widget,
					    gpointer   data);
static void      gfig_paint_callback       (GtkWidget *widget,
					    gpointer   data);
static void      gfig_clear_callback       (GtkWidget *widget,
					    gpointer   data);
static void      gfig_undo_callback        (GtkWidget *widget,
					    gpointer   data);
Sven Neumann's avatar
Sven Neumann committed
126
static gboolean  pic_preview_expose        (GtkWidget *widget,
127
					    GdkEvent  *event);
Sven Neumann's avatar
Sven Neumann committed
128 129
static void      gfig_preview_realize      (GtkWidget *widget);
static gboolean  gfig_preview_expose       (GtkWidget *widget,
130
					    GdkEvent  *event);
Sven Neumann's avatar
Sven Neumann committed
131
static gboolean  gfig_preview_events       (GtkWidget *widget,
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
					    GdkEvent  *event);
static gint      gfig_brush_preview_events (GtkWidget *widget,
					    GdkEvent  *event);

static void      gfig_scale_update_scale   (GtkAdjustment *adjustment,
					    gdouble       *value);

static void      gfig_scale2img_update     (GtkWidget *widget,
					    gpointer   data);

static gint      gfig_invscale_x           (gint       x);
static gint      gfig_invscale_y           (gint       y);
static GdkGC *   gfig_get_grid_gc          (GtkWidget *widget,
					    gint       gctype);
static void      gfig_pos_enable           (GtkWidget *widget,
					    gpointer   data);

static gint      list_button_press         (GtkWidget      *widget,
					    GdkEventButton *event,
					    gpointer        data);

static void      rescan_button_callback    (GtkWidget *widget,
					    gpointer   data);
static void      load_button_callback      (GtkWidget *widget,
					    gpointer   data);
static void      save_button_callback      (GtkWidget *widget,
					    gpointer   data);
static void      new_button_callback       (GtkWidget *widget,
					    gpointer   data);
static void   gfig_do_delete_gfig_callback (GtkWidget *widget,
					    gboolean   delete,
					    gpointer   data);
static void      gfig_delete_gfig_callback (GtkWidget *widget,
					    gpointer   data);
static void      edit_button_callback      (GtkWidget *widget,
					    gpointer   data);
static void      merge_button_callback     (GtkWidget *widget,
					    gpointer   data);
static void      about_button_callback     (GtkWidget *widget,
					    gpointer   data);
static void      reload_button_callback    (GtkWidget *widget,
					    gpointer   data);

static void      do_gfig                   (void);
static void      dialog_update_preview     (void);

178 179 180
static void      draw_grid                 (void);
static void      draw_grid_clear           (void);
static void      toggle_show_image         (void);
181 182 183 184 185 186 187 188
static void      toggle_obj_type           (GtkWidget *widget,
					    gpointer   data);

static void      gfig_new_gc               (void);
static void      find_grid_pos             (GdkPoint  *p,
					    GdkPoint  *gp,
					    guint      state);

Manish Singh's avatar
Manish Singh committed
189

190
GimpPlugInInfo PLUG_IN_INFO =
Manish Singh's avatar
Manish Singh committed
191
{
192 193 194 195
  NULL,  /* init_proc  */
  NULL,  /* quit_proc  */
  query, /* query_proc */
  run,   /* run_proc   */
Manish Singh's avatar
Manish Singh committed
196 197
};

198
#define GRID_TYPE_MENU   1
Manish Singh's avatar
Manish Singh committed
199
#define GRID_RENDER_MENU 2
200
#define GRID_IGNORE      0 
201 202
#define GRID_HIGHTLIGHT  1
#define GRID_RESTORE     2
Manish Singh's avatar
Manish Singh committed
203 204 205

#define GFIG_BLACK_GC -2
#define GFIG_WHITE_GC -3
206
#define GFIG_GREY_GC  -4
Manish Singh's avatar
Manish Singh committed
207 208

#define PAINT_LAYERS_MENU 1
209 210
#define PAINT_BGS_MENU    2
#define PAINT_TYPE_MENU   3
Manish Singh's avatar
Manish Singh committed
211

212 213
#define SELECT_TYPE_MENU      1
#define SELECT_ARCTYPE_MENU   2
Manish Singh's avatar
Manish Singh committed
214 215 216 217 218 219 220 221
#define SELECT_TYPE_MENU_FILL 3
#define SELECT_TYPE_MENU_WHEN 4

#define OBJ_SELECT_GT 1
#define OBJ_SELECT_LT 2
#define OBJ_SELECT_EQ 4

/* Must keep in step with the above */
222 223 224 225 226 227 228 229 230 231 232 233
typedef struct
{
  void      *gridspacing;
  GtkWidget *gridtypemenu;
  GtkWidget *drawgrid;
  GtkWidget *snap2grid;
  GtkWidget *lockongrid;
  GtkWidget *showcontrol;
} GfigOptWidgets;

static GfigOptWidgets gfig_opt_widget;

Manish Singh's avatar
Manish Singh committed
234
/* Values when first invoked */
235
SelectItVals selvals =
Manish Singh's avatar
Manish Singh committed
236 237
{
  {
Sven Neumann's avatar
Sven Neumann committed
238 239 240 241 242 243
    MIN_GRID + (MAX_GRID - MIN_GRID)/2, /* Gridspacing     */
    RECT_GRID,            /* Default to rectangle type     */
    FALSE,                /* drawgrid                      */
    FALSE,                /* snap2grid                     */
    FALSE,                /* lockongrid                    */
    TRUE                  /* show control points           */
Manish Singh's avatar
Manish Singh committed
244
  },
Sven Neumann's avatar
Sven Neumann committed
245
  FALSE,                  /* show image                    */
Manish Singh's avatar
Manish Singh committed
246
  MIN_UNDO + (MAX_UNDO - MIN_UNDO)/2,  /* Max level of undos */
Sven Neumann's avatar
Sven Neumann committed
247 248 249 250 251 252 253 254 255 256 257 258 259
  TRUE,                   /* Show pos updates              */
  0.0,                    /* Brush fade                    */
  0.0,                    /* Brush gradient                */
  20.0,                   /* Air bursh pressure            */
  ORIGINAL_LAYER,         /* Draw all objects on one layer */
  LAYER_TRANS_BG,         /* New layers background         */
  PAINT_BRUSH_TYPE,       /* Default to use brushes        */
  FALSE,                  /* reverse lines                 */
  TRUE,                   /* Scale to image when painting  */
  1.0,                    /* Scale to image fp             */
  FALSE,                  /* Approx circles by drawing lines */
  BRUSH_BRUSH_TYPE,       /* Default to use a brush        */
  LINE                    /* Initial object type           */
Manish Singh's avatar
Manish Singh committed
260 261
};

262
selection_option selopt =
263
{
264 265 266 267
  ADD,          /* type */
  FALSE,        /* Antia */
  FALSE,        /* Feather */
  10.0,         /* feather radius */
Manish Singh's avatar
Manish Singh committed
268 269
  ARC_SEGMENT,  /* Arc as a segment */
  FILL_PATTERN, /* Fill as pattern */
270 271
  FILL_EACH,    /* Fill after each selection */
  100.0,        /* Max opacity */
Manish Singh's avatar
Manish Singh committed
272 273 274
};


275 276
static gchar *gfig_path       = NULL;
static GList *gfig_list       = NULL;
277
gint   line_no;
Manish Singh's avatar
Manish Singh committed
278

279
static gint obj_show_single   = -1; /* -1 all >= 0 object number */
Manish Singh's avatar
Manish Singh committed
280 281 282 283 284

/* Structures etc for the objects */
/* Points used to draw the object  */


285 286
Dobject *obj_creating; /* Object we are creating */
Dobject *tmp_line;     /* Needed when drawing lines */
Manish Singh's avatar
Manish Singh committed
287

288 289
typedef struct BrushDesc
{
290 291 292 293 294 295 296 297 298
  gchar                *name;
  gdouble               opacity;
  gint                  spacing;
  GimpLayerModeEffects  paint_mode;
  gint                  width;
  gint                  height;
  guchar               *pv_buf;  /* Buffer where brush placed */
  gint16                x_off;
  gint16                y_off;
299
  const gchar          *popup;
300
} BrushDesc;
Manish Singh's avatar
Manish Singh committed
301

302

303
GFigObj  *current_obj;
304
static Dobject  *operation_obj;
Manish Singh's avatar
Manish Singh committed
305
static GdkPoint *move_all_pnt; /* Point moving all from */
306 307
static GFigObj  *pic_obj;
static DAllObjs *undo_table[MAX_UNDO];
308
gint      need_to_scale;
309 310 311
static gint32    brush_image_ID = -1;

static GtkWidget *undo_widget;
Sven Neumann's avatar
Sven Neumann committed
312 313
static GtkWidget *gfig_op_menu;    /* Popup menu in the list box */
static GtkWidget *object_list;     /* Top preview frame window */
314
static GtkWidget *fade_out_hbox;   /* Fade out widget in brush page */
BST 2000 Andy Thomas's avatar
BST 2000 Andy Thomas committed
315
static GtkWidget *gradient_hbox;   /* Gradient widget in brush page */
316 317
static GtkWidget *pressure_hbox;   /* Pressure widget in brush page */
static GtkWidget *pencil_hbox;     /* Dummy widget in brush page */
318
static GtkWidget *pos_label;       /* XY pos marker */
319 320 321
static GtkWidget *brush_page_widget; /* Widget for the brush part of notebook */
static GtkWidget *select_page_widget; /* Widget for the selection part
				       * of notebook */
Manish Singh's avatar
Manish Singh committed
322

323
static gint       undo_water_mark = -1; /* Last slot filled in -1 = no undo */
324
gint       drawing_pic = FALSE;  /* If true drawing to the small preview */
325 326 327 328
static GtkWidget *status_label_dname;
static GtkWidget *status_label_fname;
static GFigObj   *gfig_obj_for_menu; /* More static data -
				      * need to know which object was selected*/
329
static GtkWidget *save_menu_item;  
330
static GtkWidget *save_button;
Manish Singh's avatar
Manish Singh committed
331 332 333 334


/* Don't up just like BIGGG source files? */

335 336 337 338 339 340 341 342
static void       object_start            (GdkPoint *pnt, gint);
static void       object_operation        (GdkPoint *pnt, gint);
static void       object_operation_start  (GdkPoint *pnt, gint shift_down);
static void       object_operation_end    (GdkPoint *pnt, gint);
static void       object_end              (GdkPoint *pnt, gint shift_down);
static void       object_update           (GdkPoint * pnt);
static DAllObjs * copy_all_objs           (DAllObjs *objs);
static void       setup_undo              (void);
343 344
static GFigObj  * gfig_load               (const gchar *filename,
                                           const gchar *name);
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
static void       free_all_objs           (DAllObjs * objs);
static void       draw_objects            (DAllObjs *objs, gint show_single);
static GFigObj  * gfig_new                (void);
static void       clear_undo              (void);
static void       list_button_update      (GFigObj *obj);
static void       prepend_to_all_obj      (GFigObj *fobj, DAllObjs *nobj);
static void       gfig_update_stat_labels (void);
static void       gfig_obj_modified       (GFigObj *obj, gint stat_type);
static void       gfig_op_menu_create     (GtkWidget *window);
static void       gridtype_menu_callback  (GtkWidget *widget, gpointer data);
static void       draw_one_obj            (Dobject * obj);

static void       new_obj_2edit           (GFigObj *obj);
static gint       load_options            (GFigObj *gfig, FILE *fp);
static gint       gfig_obj_counts         (DAllObjs * objs);

static void    gfig_brush_fill_preview_xy (GtkWidget *pw, gint x , gint y);
Manish Singh's avatar
Manish Singh committed
362

363 364
static void      brush_list_button_callback (BrushDesc *bdesc);

Manish Singh's avatar
Manish Singh committed
365 366 367

/* globals */

368
static gint    gfig_run;
369
GdkGC  *gfig_gc;
370 371 372 373
static GdkGC  *grid_hightlight_drawgc;
static gint    grid_gc_type = GTK_STATE_NORMAL;
static guchar *pv_cache = NULL;
static guchar  preview_row[PREVIEW_SIZE*4];
Manish Singh's avatar
Manish Singh committed
374 375

/* Stuff for the preview bit */
376 377
static gint    sel_x1, sel_y1, sel_x2, sel_y2;
static gint    sel_width, sel_height;
378
gint    preview_width, preview_height;
379
static gint    has_alpha;
380
gdouble scale_x_factor, scale_y_factor;
381
static gdouble org_scale_x_factor, org_scale_y_factor;
Manish Singh's avatar
Manish Singh committed
382

Adrian Likins's avatar
Adrian Likins committed
383
MAIN ()
Manish Singh's avatar
Manish Singh committed
384 385

static void
386
query (void)
Manish Singh's avatar
Manish Singh committed
387
{
388
  static GimpParamDef args[] =
Manish Singh's avatar
Manish Singh committed
389
  {
390 391 392
    { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
    { GIMP_PDB_IMAGE, "image", "Input image (unused)" },
    { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
393
    { GIMP_PDB_INT32, "dummy", "dummy" } 
Manish Singh's avatar
Manish Singh committed
394
  };
David Monniaux's avatar
David Monniaux committed
395

Manish Singh's avatar
Manish Singh committed
396
  gimp_install_procedure ("plug_in_gfig",
Marc Lehmann's avatar
Marc Lehmann committed
397 398
			  "Create Geometrical shapes with the Gimp",
			  "More here later",
Manish Singh's avatar
Manish Singh committed
399 400 401
			  "Andy Thomas",
			  "Andy Thomas",
			  "1997",
402
			  N_("<Image>/Filters/Render/_Gfig..."),
Manish Singh's avatar
Manish Singh committed
403
			  "RGB*, GRAY*",
404
			  GIMP_PLUGIN,
405
			  G_N_ELEMENTS (args), 0,
406
			  args, NULL);
Manish Singh's avatar
Manish Singh committed
407 408 409
}

static void
410 411 412 413 414
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
Manish Singh's avatar
Manish Singh committed
415
{
416 417 418 419
  GimpParam         *values = g_new (GimpParam, 1);
  GimpDrawable      *drawable;
  GimpRunMode        run_mode;
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
Manish Singh's avatar
Manish Singh committed
420

421
  gint pwidth, pheight;
Manish Singh's avatar
Manish Singh committed
422

423
  /*kill (getpid (), 19);*/
Manish Singh's avatar
Manish Singh committed
424

425 426
  INIT_I18N ();

Manish Singh's avatar
Manish Singh committed
427 428 429 430 431 432 433
  run_mode = param[0].data.d_int32;
  gfig_image = param[1].data.d_image;
  gfig_drawable = param[2].data.d_drawable;

  *nreturn_vals = 1;
  *return_vals = values;

434
  values[0].type = GIMP_PDB_STATUS;
Manish Singh's avatar
Manish Singh committed
435 436
  values[0].data.d_status = status;

437
  gfig_select_drawable = drawable = gimp_drawable_get (param[2].data.d_drawable);
Manish Singh's avatar
Manish Singh committed
438

439 440
  tile_width  = gimp_tile_width ();
  tile_height = gimp_tile_height ();
Manish Singh's avatar
Manish Singh committed
441 442

  /* TMP Hack - clear any selections */
443 444
  if (! gimp_selection_is_empty (gfig_image))
    gimp_selection_clear (gfig_image);
Manish Singh's avatar
Manish Singh committed
445

446 447
  gimp_drawable_mask_bounds (drawable->drawable_id,
			     &sel_x1, &sel_y1, &sel_x2, &sel_y2);
Manish Singh's avatar
Manish Singh committed
448 449 450 451 452

  sel_width  = sel_x2 - sel_x1;
  sel_height = sel_y2 - sel_y1;

  /* Calculate preview size */
453
  
454 455 456 457 458 459 460 461 462
  if (sel_width > sel_height)
    {
      pwidth  = MIN (sel_width, PREVIEW_SIZE);
      pheight = sel_height * pwidth / sel_width;
    }
  else
    {
      pheight = MIN (sel_height, PREVIEW_SIZE);
      pwidth  = sel_width * pheight / sel_height;
463
    }
464
  
465
  preview_width  = MAX (pwidth, 2);  /* Min size is 2 */
466
  preview_height = MAX (pheight, 2); 
Manish Singh's avatar
Manish Singh committed
467

468 469 470 471
  org_scale_x_factor = scale_x_factor =
    (gdouble) sel_width / (gdouble) preview_width;
  org_scale_y_factor = scale_y_factor =
    (gdouble) sel_height / (gdouble) preview_height;
472

Manish Singh's avatar
Manish Singh committed
473 474
  switch (run_mode)
    {
475
    case GIMP_RUN_INTERACTIVE:
Manish Singh's avatar
Manish Singh committed
476
      /*gimp_get_data ("plug_in_gfig", &selvals);*/
477
      if (! gfig_dialog ())
Manish Singh's avatar
Manish Singh committed
478 479 480 481 482 483
	{
	  gimp_drawable_detach (drawable);
	  return;
	}
      break;

484 485
    case GIMP_RUN_NONINTERACTIVE:
      status = GIMP_PDB_CALLING_ERROR;
Manish Singh's avatar
Manish Singh committed
486 487
      break;

488
    case GIMP_RUN_WITH_LAST_VALS:
Manish Singh's avatar
Manish Singh committed
489 490 491 492 493 494 495
      /*gimp_get_data ("plug_in_gfig", &selvals);*/
      break;

    default:
      break;
    }

496 497
  if (gimp_drawable_is_rgb (drawable->drawable_id) ||
      gimp_drawable_is_gray (drawable->drawable_id))
Manish Singh's avatar
Manish Singh committed
498 499
    {
      /* Set the tile cache size */
500 501
      gimp_tile_cache_ntiles ((drawable->width + gimp_tile_width () - 1) /
			      gimp_tile_width ());
Manish Singh's avatar
Manish Singh committed
502

503
      do_gfig ();
Manish Singh's avatar
Manish Singh committed
504

505
      if (run_mode != GIMP_RUN_NONINTERACTIVE)
Manish Singh's avatar
Manish Singh committed
506 507 508
	gimp_displays_flush ();

#if 0
509
      if (run_mode == GIMP_RUN_INTERACTIVE)
Manish Singh's avatar
Manish Singh committed
510 511 512 513 514
	gimp_set_data ("plug_in_gfig", &selvals, sizeof (SelectItVals));
#endif /* 0 */
    }
  else
    {
515
      status = GIMP_PDB_EXECUTION_ERROR;
Manish Singh's avatar
Manish Singh committed
516 517 518 519 520 521 522 523 524
    }

  values[0].data.d_status = status;

  gimp_drawable_detach (drawable);
}

/*
  Translate SPACE to "\\040", etc.
Manish Singh's avatar
Manish Singh committed
525
  Taken from gflare plugin
Manish Singh's avatar
Manish Singh committed
526
 */
527 528 529
static void
gfig_name_encode (gchar *dest,
		  gchar *src)
Manish Singh's avatar
Manish Singh committed
530
{
531
  gint cnt = MAX_LOAD_LINE - 1;
Manish Singh's avatar
Manish Singh committed
532 533 534

  while (*src && cnt--)
    {
535
      if (g_ascii_iscntrl (*src) || g_ascii_isspace (*src) || *src == '\\')
Manish Singh's avatar
Manish Singh committed
536 537 538 539 540 541 542 543 544 545 546 547 548
	{
	  sprintf (dest, "\\%03o", *src++);
	  dest += 4;
	}
      else
	*dest++ = *src++;
    }
  *dest = '\0';
}

/*
  Translate "\\040" to SPACE, etc.
 */
549
static void
550 551
gfig_name_decode (gchar       *dest,
		  const gchar *src)
Manish Singh's avatar
Manish Singh committed
552
{
553 554
  gint  cnt = MAX_LOAD_LINE - 1;
  guint tmp;
Manish Singh's avatar
Manish Singh committed
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576

  while (*src && cnt--)
    {
      if (*src == '\\' && *(src+1) && *(src+2) && *(src+3))
	{
	  sscanf (src+1, "%3o", &tmp);
	  *dest++ = tmp;
	  src += 4;
	}
      else
	*dest++ = *src++;
    }
  *dest = '\0';
}


/*
 * Load all gfig, which are founded in gfig-path-list, into gfig_list.
 * gfig-path-list must be initialized first. (plug_in_parse_gfig_path ())
 * based on code from Gflare.
 */

577 578
static gint
gfig_list_pos (GFigObj *gfig)
Manish Singh's avatar
Manish Singh committed
579
{
580 581
  GFigObj *g;
  gint n;
Manish Singh's avatar
Manish Singh committed
582 583 584
  GList *tmp;

  n = 0;
585

586
  for (tmp = gfig_list; tmp; tmp = g_list_next (tmp)) 
Manish Singh's avatar
Manish Singh committed
587 588
    {
      g = tmp->data;
589
      
Manish Singh's avatar
Manish Singh committed
590 591
      if (strcmp (gfig->draw_name, g->draw_name) <= 0)
	break;
592

Manish Singh's avatar
Manish Singh committed
593 594
      n++;
    }
595
  return n;
Manish Singh's avatar
Manish Singh committed
596 597
}

598 599 600 601
/*
 *	Insert gfigs in alphabetical order
 */

602 603
static gint
gfig_list_insert (GFigObj *gfig)
Manish Singh's avatar
Manish Singh committed
604
{
605
  gint n;
Manish Singh's avatar
Manish Singh committed
606

607
  n = gfig_list_pos (gfig);
Manish Singh's avatar
Manish Singh committed
608 609 610 611 612 613

  gfig_list = g_list_insert (gfig_list, gfig, n);

  return n;
}

614 615
static void
gfig_free (GFigObj *gfig)
Manish Singh's avatar
Manish Singh committed
616 617 618
{
  g_assert (gfig != NULL);

619
  free_all_objs (gfig->obj_list);
620 621 622 623 624

  g_free (gfig->name);
  g_free (gfig->filename);
  g_free (gfig->draw_name);

Manish Singh's avatar
Manish Singh committed
625 626 627
  g_free (gfig);
}

628 629
static void
gfig_free_everything (GFigObj *gfig)
Manish Singh's avatar
Manish Singh committed
630 631 632
{
  g_assert (gfig != NULL);

633
  if (gfig->filename)
Manish Singh's avatar
Manish Singh committed
634
    {
635
      remove (gfig->filename);
Manish Singh's avatar
Manish Singh committed
636
    }
637
  gfig_free (gfig);
Manish Singh's avatar
Manish Singh committed
638 639
}

640 641
static void
gfig_list_free_all (void)
Manish Singh's avatar
Manish Singh committed
642
{
643
  g_list_foreach (gfig_list, (GFunc) gfig_free, NULL);
Manish Singh's avatar
Manish Singh committed
644 645 646 647
  g_list_free (gfig_list);
  gfig_list = NULL;
}

648
static void
649 650
gfig_list_load_one (const GimpDatafileData *file_data,
                    gpointer                user_data)
Manish Singh's avatar
Manish Singh committed
651
{
652
  GFigObj *gfig;
Manish Singh's avatar
Manish Singh committed
653

654
  gfig = gfig_load (file_data->filename, file_data->basename);
Manish Singh's avatar
Manish Singh committed
655

656
  if (gfig)
Manish Singh's avatar
Manish Singh committed
657
    {
658 659 660
      /* Read only ?*/
      if (access (file_data->filename, W_OK))
        gfig->obj_status |= GFIG_READONLY;
Manish Singh's avatar
Manish Singh committed
661

662 663 664
      gfig_list_insert (gfig);
    }
}
Manish Singh's avatar
Manish Singh committed
665

666 667 668 669 670 671
static void
gfig_list_load_all (const gchar *path)
{
  /*  Make sure to clear any existing gfigs  */
  current_obj = pic_obj = NULL;
  gfig_list_free_all ();
Manish Singh's avatar
Manish Singh committed
672

673 674 675
  gimp_datafiles_read_directories (path, G_FILE_TEST_EXISTS,
                                   gfig_list_load_one,
                                   NULL);
Manish Singh's avatar
Manish Singh committed
676

677
  if (! gfig_list)
Manish Singh's avatar
Manish Singh committed
678
    {
679 680
      GFigObj *gfig;

Manish Singh's avatar
Manish Singh committed
681
      /* lets have at least one! */
682 683 684
      gfig = gfig_new ();
      gfig->draw_name = g_strdup (_("First Gfig"));
      gfig_list_insert (gfig);
Manish Singh's avatar
Manish Singh committed
685 686
    }

687
  pic_obj = current_obj = gfig_list->data;  /* set to first entry */
Manish Singh's avatar
Manish Singh committed
688 689
}

690 691
static GFigObj *
gfig_new (void)
Manish Singh's avatar
Manish Singh committed
692
{
693
  return g_new0 (GFigObj, 1);
Manish Singh's avatar
Manish Singh committed
694 695
}

696 697 698 699
static void
gfig_load_objs (GFigObj *gfig,
		gint     load_count,
		FILE    *fp)
Manish Singh's avatar
Manish Singh committed
700
{
701
  Dobject *obj;
Manish Singh's avatar
Manish Singh committed
702 703 704
  gchar load_buf[MAX_LOAD_LINE];

  /* Loading object */
705
  /*kill (getpid (), 19);*/
Manish Singh's avatar
Manish Singh committed
706
  /* Read first line */
707
  while (load_count-- > 0)
Manish Singh's avatar
Manish Singh committed
708 709
    {
      obj = NULL;
710 711 712
      get_line (load_buf, MAX_LOAD_LINE, fp, 0);

      if (!strcmp (load_buf, "<LINE>"))
Manish Singh's avatar
Manish Singh committed
713
	{
714
	  obj = d_load_line (fp);
Manish Singh's avatar
Manish Singh committed
715
	}
716
      else if (!strcmp (load_buf, "<CIRCLE>"))
Manish Singh's avatar
Manish Singh committed
717
	{
718
	  obj = d_load_circle (fp);
Manish Singh's avatar
Manish Singh committed
719
	}
720
      else if (!strcmp (load_buf, "<ELLIPSE>"))
Manish Singh's avatar
Manish Singh committed
721
	{
722
	  obj = d_load_ellipse (fp);
Manish Singh's avatar
Manish Singh committed
723
	}
724
      else if (!strcmp (load_buf, "<POLY>"))
Manish Singh's avatar
Manish Singh committed
725
	{
726
	  obj = d_load_poly (fp);
Manish Singh's avatar
Manish Singh committed
727
	}
728
      else if (!strcmp (load_buf, "<STAR>"))
Manish Singh's avatar
Manish Singh committed
729
	{
730
	  obj = d_load_star (fp);
Manish Singh's avatar
Manish Singh committed
731
	}
732
      else if (!strcmp (load_buf, "<SPIRAL>"))
Manish Singh's avatar
Manish Singh committed
733
	{
734
	  obj = d_load_spiral (fp);
Manish Singh's avatar
Manish Singh committed
735
	}
736
      else if (!strcmp (load_buf, "<BEZIER>"))
Manish Singh's avatar
Manish Singh committed
737
	{
738
	  obj = d_load_bezier (fp);
Manish Singh's avatar
Manish Singh committed
739
	}
740
      else if (!strcmp (load_buf, "<ARC>"))
Manish Singh's avatar
Manish Singh committed
741
	{
742
	  obj = d_load_arc (fp);
Manish Singh's avatar
Manish Singh committed
743 744 745
	}
      else
	{
746
	  g_warning ("Unknown obj type file %s line %d\n", gfig->filename, line_no);
Manish Singh's avatar
Manish Singh committed
747
	}
748
      
749
      if (obj)
Manish Singh's avatar
Manish Singh committed
750
	{
751
	  add_to_all_obj (gfig, obj);
Manish Singh's avatar
Manish Singh committed
752 753 754 755
	}
    }
}

756
static GFigObj *
757 758
gfig_load (const gchar *filename,
           const gchar *name)
Manish Singh's avatar
Manish Singh committed
759
{
760 761 762 763 764 765 766
  GFigObj *gfig;
  FILE    *fp;
  gchar    load_buf[MAX_LOAD_LINE];
  gchar    str_buf[MAX_LOAD_LINE];
  gint     chk_count;
  gint     load_count = 0;

Manish Singh's avatar
Manish Singh committed
767 768 769
  g_assert (filename != NULL);

#ifdef DEBUG
770
  printf ("Loading %s (%s)\n", filename, name);
Manish Singh's avatar
Manish Singh committed
771 772 773 774 775 776 777 778 779
#endif /* DEBUG */

  fp = fopen (filename, "r");
  if (!fp)
    {
      g_warning ("Error opening: %s", filename);
      return NULL;
    }

780
  gfig = gfig_new ();
Manish Singh's avatar
Manish Singh committed
781

782 783
  gfig->name = g_strdup (name);
  gfig->filename = g_strdup (filename);
Manish Singh's avatar
Manish Singh committed
784 785 786 787 788 789 790 791


  /* HEADER
   * draw_name
   * version
   * obj_list
   */

792
  get_line (load_buf, MAX_LOAD_LINE, fp, 1);
Manish Singh's avatar
Manish Singh committed
793

794
  if (strncmp (GFIG_HEADER, load_buf, strlen (load_buf)))
Manish Singh's avatar
Manish Singh committed
795
    {
796 797
      g_message ("File '%s' is not a gfig file", gfig->filename);
      return NULL;
Manish Singh's avatar
Manish Singh committed
798
    }
799
  
800 801 802 803
  get_line (load_buf, MAX_LOAD_LINE, fp, 0);
  sscanf (load_buf, "Name: %100s", str_buf);
  gfig_name_decode (load_buf, str_buf);
  gfig->draw_name = g_strdup (load_buf);
Manish Singh's avatar
Manish Singh committed
804

805
  get_line (load_buf, MAX_LOAD_LINE, fp, 0);
806 807
  if (strncmp (load_buf, "Version: ", 9) == 0)
    gfig->version = g_ascii_strtod (load_buf + 9, NULL);
Manish Singh's avatar
Manish Singh committed
808

809 810
  get_line (load_buf, MAX_LOAD_LINE, fp, 0);
  sscanf (load_buf, "ObjCount: %d", &load_count);
Manish Singh's avatar
Manish Singh committed
811

812
  if (load_options (gfig, fp))
Manish Singh's avatar
Manish Singh committed
813
    {
814 815 816
      g_message ("File '%s' corrupt file - Line %d Option section incorrect",
		 filename, line_no);
      return NULL;
Manish Singh's avatar
Manish Singh committed
817 818
    }

819
  /*return (NULL);*/
Manish Singh's avatar
Manish Singh committed
820

821
  gfig_load_objs (gfig, load_count, fp);
Manish Singh's avatar
Manish Singh committed
822 823

  /* Check count ? */
824
  
825
  chk_count = gfig_obj_counts (gfig->obj_list);
Manish Singh's avatar
Manish Singh committed
826

827
  if (chk_count != load_count)
Manish Singh's avatar
Manish Singh committed
828
    {
829 830 831
      g_message ("File '%s' corrupt file - Line %d Object count to small",
		 filename, line_no);
      return NULL;
Manish Singh's avatar
Manish Singh committed
832 833
    }

834
  fclose (fp);
Manish Singh's avatar
Manish Singh committed
835

836
  if (!pic_obj)
Manish Singh's avatar
Manish Singh committed
837 838 839 840
    pic_obj = gfig;

  gfig->obj_status = GFIG_OK;

841
  return gfig;
Manish Singh's avatar
Manish Singh committed
842 843
}

844 845
static void
save_options (FILE *fp)
Manish Singh's avatar
Manish Singh committed
846 847
{
  /* Save options */
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
  fprintf (fp, "<OPTIONS>\n");
  fprintf (fp, "GridSpacing: %d\n", selvals.opts.gridspacing);
  if (selvals.opts.gridtype == RECT_GRID)
    fprintf (fp, "GridType: RECT_GRID\n");
  else if (selvals.opts.gridtype == POLAR_GRID)
    fprintf (fp, "GridType: POLAR_GRID\n");
  else if (selvals.opts.gridtype == ISO_GRID)
    fprintf (fp, "GridType: ISO_GRID\n");
  else fprintf (fp, "GridType: RECT_GRID\n"); /* If in doubt, default to RECT_GRID */
  fprintf (fp, "DrawGrid: %s\n", (selvals.opts.drawgrid)?"TRUE":"FALSE");
  fprintf (fp, "Snap2Grid: %s\n", (selvals.opts.snap2grid)?"TRUE":"FALSE");
  fprintf (fp, "LockOnGrid: %s\n", (selvals.opts.lockongrid)?"TRUE":"FALSE");
  /*  fprintf (fp, "ShowImage: %s\n", (selvals.opts.showimage)?"TRUE":"FALSE");*/
  fprintf (fp, "ShowControl: %s\n", (selvals.opts.showcontrol)?"TRUE":"FALSE");
  fprintf (fp, "</OPTIONS>\n");
}

static gint
load_bool (gchar *opt_buf,
	   gint  *toset)
{
  if (!strcmp (opt_buf, "TRUE"))
Manish Singh's avatar
Manish Singh committed
870
    *toset = 1;
871
  else if (!strcmp (opt_buf, "FALSE"))
Manish Singh's avatar
Manish Singh committed
872 873
    *toset = 0;
  else
874
    return (-1);
Manish Singh's avatar
Manish Singh committed
875

876
  return (0);
Manish Singh's avatar
Manish Singh committed
877 878 879
}

static void
880
update_options (GFigObj *old_obj)
Manish Singh's avatar
Manish Singh committed
881 882
{
  /* Save old vals */
883
  if (selvals.opts.gridspacing != old_obj->opts.gridspacing)