gfig.c 146 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
#include "gfig.h"
57 58 59 60 61 62 63 64 65
#include "gfig-arc.h"
#include "gfig-bezier.h"
#include "gfig-circle.h"
#include "gfig-dobject.h"
#include "gfig-ellipse.h"
#include "gfig-line.h"
#include "gfig-poly.h"
#include "gfig-spiral.h"
#include "gfig-star.h"
66 67
#include "gfig-stock.h"

68
#include "pix-data.h"
Manish Singh's avatar
Manish Singh committed
69

70

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

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

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

84 85 86 87 88 89 90
/* 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 */

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

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

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
					    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);
141 142
static gint      gfig_scale_x    	   (gint       x);
static gint      gfig_scale_y    	   (gint       y);
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 178
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);

179 180
static void      draw_grid                 (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
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 305
static GFigObj  *pic_obj;
static DAllObjs *undo_table[MAX_UNDO];
306
gint      need_to_scale;
307 308 309
static gint32    brush_image_ID = -1;

static GtkWidget *undo_widget;
Sven Neumann's avatar
Sven Neumann committed
310 311
static GtkWidget *gfig_op_menu;    /* Popup menu in the list box */
static GtkWidget *object_list;     /* Top preview frame window */
312
static GtkWidget *fade_out_hbox;   /* Fade out widget in brush page */
BST 2000 Andy Thomas's avatar
BST 2000 Andy Thomas committed
313
static GtkWidget *gradient_hbox;   /* Gradient widget in brush page */
314 315
static GtkWidget *pressure_hbox;   /* Pressure widget in brush page */
static GtkWidget *pencil_hbox;     /* Dummy widget in brush page */
316
static GtkWidget *pos_label;       /* XY pos marker */
317 318 319
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
320

321
static gint       undo_water_mark = -1; /* Last slot filled in -1 = no undo */
322
gboolean       drawing_pic = FALSE;  /* If true drawing to the small preview */
323 324 325 326
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*/
327
static GtkWidget *save_menu_item;  
328
static GtkWidget *save_button;
Manish Singh's avatar
Manish Singh committed
329 330 331 332


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

333 334
static GFigObj  * gfig_load               (const gchar *filename,
                                           const gchar *name);
335 336 337 338 339 340 341 342 343 344 345 346 347 348
static void       free_all_objs           (DAllObjs * objs);
static GFigObj  * gfig_new                (void);
static void       clear_undo              (void);
static void       list_button_update      (GFigObj *obj);
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       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
349

350 351
static void      brush_list_button_callback (BrushDesc *bdesc);

Manish Singh's avatar
Manish Singh committed
352 353 354

/* globals */

355
static gint    gfig_run;
356
GdkGC  *gfig_gc;
357 358 359 360
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
361 362

/* Stuff for the preview bit */
363 364
static gint    sel_x1, sel_y1, sel_x2, sel_y2;
static gint    sel_width, sel_height;
365
gint    preview_width, preview_height;
366
static gint    has_alpha;
367
gdouble scale_x_factor, scale_y_factor;
368
static gdouble org_scale_x_factor, org_scale_y_factor;
Manish Singh's avatar
Manish Singh committed
369

Adrian Likins's avatar
Adrian Likins committed
370
MAIN ()
Manish Singh's avatar
Manish Singh committed
371 372

static void
373
query (void)
Manish Singh's avatar
Manish Singh committed
374
{
375
  static GimpParamDef args[] =
Manish Singh's avatar
Manish Singh committed
376
  {
377 378 379
    { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
    { GIMP_PDB_IMAGE, "image", "Input image (unused)" },
    { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
380
    { GIMP_PDB_INT32, "dummy", "dummy" } 
Manish Singh's avatar
Manish Singh committed
381
  };
David Monniaux's avatar
David Monniaux committed
382

Manish Singh's avatar
Manish Singh committed
383
  gimp_install_procedure ("plug_in_gfig",
Marc Lehmann's avatar
Marc Lehmann committed
384 385
			  "Create Geometrical shapes with the Gimp",
			  "More here later",
Manish Singh's avatar
Manish Singh committed
386 387 388
			  "Andy Thomas",
			  "Andy Thomas",
			  "1997",
389
			  N_("<Image>/Filters/Render/_Gfig..."),
Manish Singh's avatar
Manish Singh committed
390
			  "RGB*, GRAY*",
391
			  GIMP_PLUGIN,
392
			  G_N_ELEMENTS (args), 0,
393
			  args, NULL);
Manish Singh's avatar
Manish Singh committed
394 395 396
}

static void
397 398 399 400 401
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
Manish Singh's avatar
Manish Singh committed
402
{
403 404 405 406
  GimpParam         *values = g_new (GimpParam, 1);
  GimpDrawable      *drawable;
  GimpRunMode        run_mode;
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
Manish Singh's avatar
Manish Singh committed
407

408
  gint pwidth, pheight;
Manish Singh's avatar
Manish Singh committed
409

410 411
  INIT_I18N ();

Manish Singh's avatar
Manish Singh committed
412 413 414 415 416 417 418
  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;

419
  values[0].type = GIMP_PDB_STATUS;
Manish Singh's avatar
Manish Singh committed
420 421
  values[0].data.d_status = status;

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

  /* TMP Hack - clear any selections */
425 426
  if (! gimp_selection_is_empty (gfig_image))
    gimp_selection_clear (gfig_image);
Manish Singh's avatar
Manish Singh committed
427

428 429
  gimp_drawable_mask_bounds (drawable->drawable_id,
			     &sel_x1, &sel_y1, &sel_x2, &sel_y2);
Manish Singh's avatar
Manish Singh committed
430 431 432 433 434

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

  /* Calculate preview size */
435
  
436 437 438 439 440 441 442 443 444
  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;
445
    }
446
  
447
  preview_width  = MAX (pwidth, 2);  /* Min size is 2 */
448
  preview_height = MAX (pheight, 2); 
Manish Singh's avatar
Manish Singh committed
449

450 451 452 453
  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;
454

Manish Singh's avatar
Manish Singh committed
455 456
  switch (run_mode)
    {
457
    case GIMP_RUN_INTERACTIVE:
Manish Singh's avatar
Manish Singh committed
458
      /*gimp_get_data ("plug_in_gfig", &selvals);*/
459
      if (! gfig_dialog ())
Manish Singh's avatar
Manish Singh committed
460 461 462 463 464 465
	{
	  gimp_drawable_detach (drawable);
	  return;
	}
      break;

466 467
    case GIMP_RUN_NONINTERACTIVE:
      status = GIMP_PDB_CALLING_ERROR;
Manish Singh's avatar
Manish Singh committed
468 469
      break;

470
    case GIMP_RUN_WITH_LAST_VALS:
Manish Singh's avatar
Manish Singh committed
471 472 473 474 475 476 477
      /*gimp_get_data ("plug_in_gfig", &selvals);*/
      break;

    default:
      break;
    }

478 479
  if (gimp_drawable_is_rgb (drawable->drawable_id) ||
      gimp_drawable_is_gray (drawable->drawable_id))
Manish Singh's avatar
Manish Singh committed
480 481
    {
      /* Set the tile cache size */
482 483
      gimp_tile_cache_ntiles ((drawable->width + gimp_tile_width () - 1) /
			      gimp_tile_width ());
Manish Singh's avatar
Manish Singh committed
484

485
      do_gfig ();
Manish Singh's avatar
Manish Singh committed
486

487
      if (run_mode != GIMP_RUN_NONINTERACTIVE)
Manish Singh's avatar
Manish Singh committed
488 489 490
	gimp_displays_flush ();

#if 0
491
      if (run_mode == GIMP_RUN_INTERACTIVE)
Manish Singh's avatar
Manish Singh committed
492 493 494 495 496
	gimp_set_data ("plug_in_gfig", &selvals, sizeof (SelectItVals));
#endif /* 0 */
    }
  else
    {
497
      status = GIMP_PDB_EXECUTION_ERROR;
Manish Singh's avatar
Manish Singh committed
498 499 500 501 502 503 504 505 506
    }

  values[0].data.d_status = status;

  gimp_drawable_detach (drawable);
}

/*
  Translate SPACE to "\\040", etc.
Manish Singh's avatar
Manish Singh committed
507
  Taken from gflare plugin
Manish Singh's avatar
Manish Singh committed
508
 */
509 510 511
static void
gfig_name_encode (gchar *dest,
		  gchar *src)
Manish Singh's avatar
Manish Singh committed
512
{
513
  gint cnt = MAX_LOAD_LINE - 1;
Manish Singh's avatar
Manish Singh committed
514 515 516

  while (*src && cnt--)
    {
517
      if (g_ascii_iscntrl (*src) || g_ascii_isspace (*src) || *src == '\\')
Manish Singh's avatar
Manish Singh committed
518 519 520 521 522 523 524 525 526 527 528 529 530
	{
	  sprintf (dest, "\\%03o", *src++);
	  dest += 4;
	}
      else
	*dest++ = *src++;
    }
  *dest = '\0';
}

/*
  Translate "\\040" to SPACE, etc.
 */
531
static void
532 533
gfig_name_decode (gchar       *dest,
		  const gchar *src)
Manish Singh's avatar
Manish Singh committed
534
{
535 536
  gint  cnt = MAX_LOAD_LINE - 1;
  guint tmp;
Manish Singh's avatar
Manish Singh committed
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558

  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.
 */

559 560
static gint
gfig_list_pos (GFigObj *gfig)
Manish Singh's avatar
Manish Singh committed
561
{
562 563
  GFigObj *g;
  gint n;
Manish Singh's avatar
Manish Singh committed
564 565 566
  GList *tmp;

  n = 0;
567

568
  for (tmp = gfig_list; tmp; tmp = g_list_next (tmp)) 
Manish Singh's avatar
Manish Singh committed
569 570
    {
      g = tmp->data;
571
      
Manish Singh's avatar
Manish Singh committed
572 573
      if (strcmp (gfig->draw_name, g->draw_name) <= 0)
	break;
574

Manish Singh's avatar
Manish Singh committed
575 576
      n++;
    }
577
  return n;
Manish Singh's avatar
Manish Singh committed
578 579
}

580 581 582 583
/*
 *	Insert gfigs in alphabetical order
 */

584 585
static gint
gfig_list_insert (GFigObj *gfig)
Manish Singh's avatar
Manish Singh committed
586
{
587
  gint n;
Manish Singh's avatar
Manish Singh committed
588

589
  n = gfig_list_pos (gfig);
Manish Singh's avatar
Manish Singh committed
590 591 592 593 594 595

  gfig_list = g_list_insert (gfig_list, gfig, n);

  return n;
}

596 597
static void
gfig_free (GFigObj *gfig)
Manish Singh's avatar
Manish Singh committed
598 599 600
{
  g_assert (gfig != NULL);

601
  free_all_objs (gfig->obj_list);
602 603 604 605 606

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

Manish Singh's avatar
Manish Singh committed
607 608 609
  g_free (gfig);
}

610 611
static void
gfig_free_everything (GFigObj *gfig)
Manish Singh's avatar
Manish Singh committed
612 613 614
{
  g_assert (gfig != NULL);

615
  if (gfig->filename)
Manish Singh's avatar
Manish Singh committed
616
    {
617
      remove (gfig->filename);
Manish Singh's avatar
Manish Singh committed
618
    }
619
  gfig_free (gfig);
Manish Singh's avatar
Manish Singh committed
620 621
}

622 623
static void
gfig_list_free_all (void)
Manish Singh's avatar
Manish Singh committed
624
{
625
  g_list_foreach (gfig_list, (GFunc) gfig_free, NULL);
Manish Singh's avatar
Manish Singh committed
626 627 628 629
  g_list_free (gfig_list);
  gfig_list = NULL;
}

630
static void
631 632
gfig_list_load_one (const GimpDatafileData *file_data,
                    gpointer                user_data)
Manish Singh's avatar
Manish Singh committed
633
{
634
  GFigObj *gfig;
Manish Singh's avatar
Manish Singh committed
635

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

638
  if (gfig)
Manish Singh's avatar
Manish Singh committed
639
    {
640 641 642
      /* Read only ?*/
      if (access (file_data->filename, W_OK))
        gfig->obj_status |= GFIG_READONLY;
Manish Singh's avatar
Manish Singh committed
643

644 645 646
      gfig_list_insert (gfig);
    }
}
Manish Singh's avatar
Manish Singh committed
647

648 649 650 651 652 653
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
654

655 656 657
  gimp_datafiles_read_directories (path, G_FILE_TEST_EXISTS,
                                   gfig_list_load_one,
                                   NULL);
Manish Singh's avatar
Manish Singh committed
658

659
  if (! gfig_list)
Manish Singh's avatar
Manish Singh committed
660
    {
661 662
      GFigObj *gfig;

Manish Singh's avatar
Manish Singh committed
663
      /* lets have at least one! */
664 665 666
      gfig = gfig_new ();
      gfig->draw_name = g_strdup (_("First Gfig"));
      gfig_list_insert (gfig);
Manish Singh's avatar
Manish Singh committed
667 668
    }

669
  pic_obj = current_obj = gfig_list->data;  /* set to first entry */
Manish Singh's avatar
Manish Singh committed
670 671
}

672 673
static GFigObj *
gfig_new (void)
Manish Singh's avatar
Manish Singh committed
674
{
675
  return g_new0 (GFigObj, 1);
Manish Singh's avatar
Manish Singh committed
676 677
}

678 679 680 681
static void
gfig_load_objs (GFigObj *gfig,
		gint     load_count,
		FILE    *fp)
Manish Singh's avatar
Manish Singh committed
682
{
683
  Dobject *obj;
Manish Singh's avatar
Manish Singh committed
684 685 686
  gchar load_buf[MAX_LOAD_LINE];

  /* Loading object */
687
  /*kill (getpid (), 19);*/
Manish Singh's avatar
Manish Singh committed
688
  /* Read first line */
689
  while (load_count-- > 0)
Manish Singh's avatar
Manish Singh committed
690 691
    {
      obj = NULL;
692 693 694
      get_line (load_buf, MAX_LOAD_LINE, fp, 0);

      if (!strcmp (load_buf, "<LINE>"))
Manish Singh's avatar
Manish Singh committed
695
	{
696
	  obj = d_load_line (fp);
Manish Singh's avatar
Manish Singh committed
697
	}
698
      else if (!strcmp (load_buf, "<CIRCLE>"))
Manish Singh's avatar
Manish Singh committed
699
	{
700
	  obj = d_load_circle (fp);
Manish Singh's avatar
Manish Singh committed
701
	}
702
      else if (!strcmp (load_buf, "<ELLIPSE>"))
Manish Singh's avatar
Manish Singh committed
703
	{
704
	  obj = d_load_ellipse (fp);
Manish Singh's avatar
Manish Singh committed
705
	}
706
      else if (!strcmp (load_buf, "<POLY>"))
Manish Singh's avatar
Manish Singh committed
707
	{
708
	  obj = d_load_poly (fp);
Manish Singh's avatar
Manish Singh committed
709
	}
710
      else if (!strcmp (load_buf, "<STAR>"))
Manish Singh's avatar
Manish Singh committed
711
	{
712
	  obj = d_load_star (fp);
Manish Singh's avatar
Manish Singh committed
713
	}
714
      else if (!strcmp (load_buf, "<SPIRAL>"))
Manish Singh's avatar
Manish Singh committed
715
	{
716
	  obj = d_load_spiral (fp);
Manish Singh's avatar
Manish Singh committed
717
	}
718
      else if (!strcmp (load_buf, "<BEZIER>"))
Manish Singh's avatar
Manish Singh committed
719
	{
720
	  obj = d_load_bezier (fp);
Manish Singh's avatar
Manish Singh committed
721
	}
722
      else if (!strcmp (load_buf, "<ARC>"))
Manish Singh's avatar
Manish Singh committed
723
	{
724
	  obj = d_load_arc (fp);
Manish Singh's avatar
Manish Singh committed
725 726 727
	}
      else
	{
728
	  g_warning ("Unknown obj type file %s line %d\n", gfig->filename, line_no);
Manish Singh's avatar
Manish Singh committed
729
	}
730
      
731
      if (obj)
Manish Singh's avatar
Manish Singh committed
732
	{
733
	  add_to_all_obj (gfig, obj);
Manish Singh's avatar
Manish Singh committed
734 735 736 737
	}
    }
}

738
static GFigObj *
739 740
gfig_load (const gchar *filename,
           const gchar *name)
Manish Singh's avatar
Manish Singh committed
741
{
742 743 744 745 746 747 748
  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
749 750 751
  g_assert (filename != NULL);

#ifdef DEBUG
752
  printf ("Loading %s (%s)\n", filename, name);
Manish Singh's avatar
Manish Singh committed
753 754 755 756 757 758 759 760 761
#endif /* DEBUG */

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

762
  gfig = gfig_new ();
Manish Singh's avatar
Manish Singh committed
763

764 765
  gfig->name = g_strdup (name);
  gfig->filename = g_strdup (filename);
Manish Singh's avatar
Manish Singh committed
766 767 768 769 770 771 772 773


  /* HEADER
   * draw_name
   * version
   * obj_list
   */

774
  get_line (load_buf, MAX_LOAD_LINE, fp, 1);
Manish Singh's avatar
Manish Singh committed
775

776
  if (strncmp (GFIG_HEADER, load_buf, strlen (load_buf)))
Manish Singh's avatar
Manish Singh committed
777
    {
778 779
      g_message ("File '%s' is not a gfig file", gfig->filename);
      return NULL;
Manish Singh's avatar
Manish Singh committed
780
    }
781
  
782 783 784 785
  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
786

787
  get_line (load_buf, MAX_LOAD_LINE, fp, 0);
788 789
  if (strncmp (load_buf, "Version: ", 9) == 0)
    gfig->version = g_ascii_strtod (load_buf + 9, NULL);
Manish Singh's avatar
Manish Singh committed
790

791 792
  get_line (load_buf, MAX_LOAD_LINE, fp, 0);
  sscanf (load_buf, "ObjCount: %d", &load_count);
Manish Singh's avatar
Manish Singh committed
793

794
  if (load_options (gfig, fp))
Manish Singh's avatar
Manish Singh committed
795
    {
796 797 798
      g_message ("File '%s' corrupt file - Line %d Option section incorrect",
		 filename, line_no);
      return NULL;
Manish Singh's avatar
Manish Singh committed
799 800
    }

801
  /*return (NULL);*/
Manish Singh's avatar
Manish Singh committed
802

803
  gfig_load_objs (gfig, load_count, fp);
Manish Singh's avatar
Manish Singh committed
804 805

  /* Check count ? */
806
  
807
  chk_count = gfig_obj_counts (gfig->obj_list);
Manish Singh's avatar
Manish Singh committed
808

809
  if (chk_count != load_count)
Manish Singh's avatar
Manish Singh committed
810
    {
811 812 813
      g_message ("File '%s' corrupt file - Line %d Object count to small",
		 filename, line_no);
      return NULL;
Manish Singh's avatar
Manish Singh committed
814 815
    }

816
  fclose (fp);
Manish Singh's avatar
Manish Singh committed
817

818
  if (!pic_obj)
Manish Singh's avatar
Manish Singh committed
819 820 821 822
    pic_obj = gfig;

  gfig->obj_status = GFIG_OK;

823
  return gfig;
Manish Singh's avatar
Manish Singh committed
824 825
}

826 827
static void
save_options (FILE *fp)
Manish Singh's avatar
Manish Singh committed
828 829
{
  /* Save options */
830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
  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
852
    *toset = 1;
853
  else if (!strcmp (opt_buf, "FALSE"))
Manish Singh's avatar
Manish Singh committed
854 855
    *toset = 0;
  else
856
    return (-1);
Manish Singh's avatar
Manish Singh committed
857

858
  return (0);
Manish Singh's avatar
Manish Singh committed
859 860 861
}

static void
862
update_options (GFigObj *old_obj)
Manish Singh's avatar
Manish Singh committed
863 864
{
  /* Save old vals */
865
  if (selvals.opts.gridspacing != old_obj->opts.gridspacing)
Manish Singh's avatar
Manish Singh committed
866 867 868
    {
      old_obj->opts.gridspacing = selvals.opts.gridspacing;
    }
869
  if (selvals.opts.gridtype != old_obj->opts.gridtype)
Manish Singh's avatar
Manish Singh committed
870 871 872
    {
      old_obj->opts.gridtype = selvals.opts.gridtype;
    }
873
  if (selvals.opts.drawgrid != old_obj->opts.drawgrid)
Manish Singh's avatar
Manish Singh committed
874 875 876
    {
      old_obj->opts.drawgrid = selvals.opts.drawgrid;
    }
877
  if (selvals.opts.snap2grid != old_obj->opts.snap2grid)