gerbv  2.10.1-dev~93f1b5
gerbv.c
Go to the documentation of this file.
1 /*
2  * gEDA - GNU Electronic Design Automation
3  * This file is a part of gerbv.
4  *
5  * Copyright (C) 2000-2003 Stefan Petersen (spe@stacken.kth.se)
6  *
7  * $Id$
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
22  */
23 
29 #include "gerbv.h"
30 
31 #include <assert.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <math.h>
35 #include <errno.h>
36 
37 #ifdef HAVE_LIBGEN_H
38 #include <libgen.h> /* dirname */
39 #endif
40 
41 #ifdef HAVE_STRING_H
42 #include <string.h>
43 #endif
44 
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48 
49 #ifdef HAVE_GETOPT_H
50 #include <getopt.h>
51 #endif
52 
53 #include <pango/pango.h>
54 
55 #include "common.h"
56 #include "gerber.h"
57 #include "drill.h"
58 #include "selection.h"
59 
60 #include "draw-gdk.h"
61 #include "draw.h"
62 
63 #include "pick-and-place.h"
64 
65 /* DEBUG printing. #define DEBUG 1 in config.h to use this fcn. */
66 #define dprintf \
67  if (DEBUG) \
68  printf
69 
71 const char*
73  /* These are the names of the valid apertures. Please keep this in
74  * sync with the gerbv_aperture_type_t enum defined in gerbv.h */
75  const char* names[] = {
76  N_("none"), N_("circle"), N_("rectangle"), N_("oval"), /* ovular (obround) aperture */
77  N_("polygon"), /* polygon aperture */
78  N_("macro"), /* RS274X macro */
79  N_("circle macro"), /* RS274X circle macro */
80  N_("outline macro"), /* RS274X outline macro */
81  N_("polygon macro"), /* RS274X polygon macro */
82  N_("moire macro"), /* RS274X moire macro */
83  N_("thermal macro"), /* RS274X thermal macro */
84  N_("line20 macro"), /* RS274X line (code 20) macro */
85  N_("line21 macro"), /* RS274X line (code 21) macro */
86  N_("line22 macro"), /* RS274X line (code 22) macro */
87  };
88 
89  if (type >= 0 && type < sizeof(names) / sizeof(names[0]))
90  return names[type];
91 
92  return N_("<undefined>");
93 }
94 
96 const char*
98  /* These are the names of the interpolation method. Please keep this
99  * in sync with the gerbv_interpolation_t enum defined in gerbv.h */
100  const char* names[] = {
101  N_("1X linear"), N_("10X linear"), N_("0.1X linear"), N_("0.01X linear"), N_("CW circular"),
102  N_("CCW circular"), N_("poly area start"), N_("poly area stop"), N_("deleted"),
103  };
104 
105  if (interp >= 0 && interp < sizeof(names) / sizeof(names[0]))
106  return names[interp];
107 
108  return N_("<undefined>");
109 }
110 
111 #define NUMBER_OF_DEFAULT_COLORS 18
112 #define NUMBER_OF_DEFAULT_TRANSFORMATIONS 20
113 
114 static int defaultColorIndex = 0;
115 
116 /* ------------------------------------------------------------------ */
117 static gerbv_layer_color defaultColors[NUMBER_OF_DEFAULT_COLORS] = {
118  {115, 115, 222, 177},
119  {255, 127, 115, 177},
120  {193, 0, 224, 177},
121  {117, 242, 103, 177},
122  { 0, 195, 195, 177},
123  {213, 253, 51, 177},
124  {209, 27, 104, 177},
125  {255, 197, 51, 177},
126  {186, 186, 186, 177},
127  {211, 211, 255, 177},
128  {253, 210, 206, 177},
129  {236, 194, 242, 177},
130  {208, 249, 204, 177},
131  {183, 255, 255, 177},
132  {241, 255, 183, 177},
133  {255, 202, 225, 177},
134  {253, 238, 197, 177},
135  {226, 226, 226, 177}
136 };
137 
138 /* ------------------------------------------------------------------ */
139 static gerbv_user_transformation_t defaultTransformations[NUMBER_OF_DEFAULT_TRANSFORMATIONS] = {
140  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
141  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
142  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
143  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
144  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
145  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
146  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
147  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
148  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
149  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
150  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
151  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
152  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
153  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
154  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
155  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
156  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
157  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
158  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
159  {0, 0, 1, 1, 0, FALSE, FALSE, FALSE},
160 };
161 
162 /* ------------------------------------------------------------------ */
165  gerbv_project_t* returnProject = (gerbv_project_t*)g_new0(gerbv_project_t, 1);
166 
167  /* default to using the current directory path for our starting guesses
168  on future file loads */
169  returnProject->path = g_get_current_dir();
170  /* Will be updated to 0 when first Gerber is loaded */
171  returnProject->last_loaded = -1;
172  returnProject->max_files = 1;
173  returnProject->check_before_delete = TRUE;
174  returnProject->file = g_new0(gerbv_fileinfo_t*, returnProject->max_files);
175 
176  return returnProject;
177 }
178 
179 /* ------------------------------------------------------------------ */
180 void
182  int i;
183 
184  /* destroy all the files attached to the project */
185  for (i = gerbvProject->last_loaded; i >= 0; i--) {
186  if (gerbvProject->file[i]) {
187  gerbv_destroy_fileinfo(gerbvProject->file[i]);
188  g_free(gerbvProject->file[i]);
189  }
190  }
191  /* destroy strings */
192  g_free(gerbvProject->path);
193  g_free(gerbvProject->execname);
194  g_free(gerbvProject->execpath);
195  g_free(gerbvProject->project);
196  /* destroy the fileinfo array */
197  g_free(gerbvProject->file);
198  g_free(gerbvProject);
199 }
200 
201 /* ------------------------------------------------------------------ */
202 void
204  gerbv_destroy_image(fileInfo->image);
205  g_free(fileInfo->fullPathname);
206  g_free(fileInfo->name);
207  if (fileInfo->privateRenderData) {
208  cairo_surface_destroy((cairo_surface_t*)fileInfo->privateRenderData);
209  }
210 }
211 
212 /* ------------------------------------------------------------------ */
213 void
214 gerbv_open_layer_from_filename(gerbv_project_t* gerbvProject, const gchar* filename) {
215  gint idx_loaded;
216  dprintf("Opening filename = %s\n", filename);
217 
218  if (gerbv_open_image(gerbvProject, filename, ++gerbvProject->last_loaded, FALSE, NULL, 0, TRUE) == -1) {
219  GERB_COMPILE_WARNING(_("Could not read \"%s\" (loaded %d)"), filename, gerbvProject->last_loaded);
220  gerbvProject->last_loaded--;
221  } else {
222  idx_loaded = gerbvProject->last_loaded;
223  gerbvProject->file[idx_loaded]->layer_dirty = FALSE;
224  dprintf(" Successfully opened file!\n");
225  }
226 } /* gerbv_open_layer_from_filename */
227 
228 /* ------------------------------------------------------------------ */
229 void
231  gerbv_project_t* gerbvProject, const gchar* filename, guint16 red, guint16 green, guint16 blue, guint16 alpha
232 ) {
233  gint idx_loaded;
234  dprintf("Opening filename = %s\n", filename);
235 
236  if (gerbv_open_image(gerbvProject, filename, ++gerbvProject->last_loaded, FALSE, NULL, 0, TRUE) == -1) {
237  GERB_COMPILE_WARNING(_("Could not read \"%s\" (loaded %d)"), filename, gerbvProject->last_loaded);
238  gerbvProject->last_loaded--;
239  } else {
240  idx_loaded = gerbvProject->last_loaded;
241  gerbvProject->file[idx_loaded]->layer_dirty = FALSE;
242  GdkColor colorTemplate = { 0, red, green, blue };
243  gerbvProject->file[idx_loaded]->color = colorTemplate;
244  gerbvProject->file[idx_loaded]->alpha = alpha;
245  dprintf(" Successfully opened file!\n");
246  }
247 } /* gerbv_open_layer_from_filename_with_color */
248 
249 /* ------------------------------------------------------------------ */
250 gboolean
251 gerbv_save_layer_from_index(gerbv_project_t* gerbvProject, gint index, gchar* filename) {
252  gerbv_fileinfo_t* file = gerbvProject->file[index];
253  gerbv_user_transformation_t* trans = &file->transform;
254 
255  switch (file->image->layertype) {
257  if (trans) {
258  /* NOTE: mirrored file is not yet supported */
259  if (trans->mirrorAroundX || trans->mirrorAroundY) {
260  GERB_COMPILE_ERROR(
261  _("Exporting mirrored file "
262  "is not supported!")
263  );
264  return FALSE;
265  }
266 
267  /* NOTE: inverted file is not yet supported */
268  if (trans->inverted) {
269  GERB_COMPILE_ERROR(
270  _("Exporting inverted file "
271  "is not supported!")
272  );
273  return FALSE;
274  }
275  }
276 
277  gerbv_export_rs274x_file_from_image(filename, file->image, trans);
278  break;
279 
281  if (trans) {
282  /* NOTE: inverted file is not yet supported */
283  if (trans->inverted) {
284  GERB_COMPILE_ERROR(
285  _("Exporting inverted file "
286  "is not supported!")
287  );
288  return FALSE;
289  }
290  }
291 
292  gerbv_export_drill_file_from_image(filename, file->image, trans);
293  break;
294  default: return FALSE;
295  }
296 
297  file->layer_dirty = FALSE;
298 
299  return TRUE;
300 }
301 
302 /* ------------------------------------------------------------------ */
303 int
304 gerbv_revert_file(gerbv_project_t* gerbvProject, int idx) {
305  int rv;
306 
307  rv = gerbv_open_image(gerbvProject, gerbvProject->file[idx]->fullPathname, idx, TRUE, NULL, 0, TRUE);
308  gerbvProject->file[idx]->layer_dirty = FALSE;
309  return rv;
310 }
311 
312 /* ------------------------------------------------------------------ */
313 void
314 gerbv_revert_all_files(gerbv_project_t* gerbvProject) {
315  int idx;
316 
317  for (idx = 0; idx <= gerbvProject->last_loaded; idx++) {
318  if (gerbvProject->file[idx] && gerbvProject->file[idx]->fullPathname) {
319  (void)gerbv_revert_file(gerbvProject, idx);
320  gerbvProject->file[idx]->layer_dirty = FALSE;
321  }
322  }
323 } /* gerbv_revert_all_files */
324 
325 /* ------------------------------------------------------------------ */
326 void
327 gerbv_unload_layer(gerbv_project_t* gerbvProject, int index) {
328  gint i;
329 
330  gerbv_destroy_fileinfo(gerbvProject->file[index]);
331 
332  /* slide all later layers down to fill the empty slot */
333  for (i = index; i < (gerbvProject->last_loaded); i++) {
334  gerbvProject->file[i] = gerbvProject->file[i + 1];
335  }
336  /* make sure the final spot is clear */
337  gerbvProject->file[gerbvProject->last_loaded] = NULL;
338  gerbvProject->last_loaded--;
339 } /* gerbv_unload_layer */
340 
341 /* ------------------------------------------------------------------ */
342 void
343 gerbv_unload_all_layers(gerbv_project_t* gerbvProject) {
344  int index;
345 
346  /* Must count down since gerbv_unload_layer collapses
347  * layers down. Otherwise, layers slide past the index */
348  for (index = gerbvProject->last_loaded; index >= 0; index--) {
349  if (gerbvProject->file[index] && gerbvProject->file[index]->name) {
350  gerbv_unload_layer(gerbvProject, index);
351  }
352  }
353 } /* gerbv_unload_all_layers */
354 
355 /* ------------------------------------------------------------------ */
356 void
357 gerbv_change_layer_order(gerbv_project_t* gerbvProject, gint oldPosition, gint newPosition) {
358  gerbv_fileinfo_t* temp_file;
359  int index;
360 
361  temp_file = gerbvProject->file[oldPosition];
362 
363  if (oldPosition < newPosition) {
364  for (index = oldPosition; index < newPosition; index++) {
365  gerbvProject->file[index] = gerbvProject->file[index + 1];
366  }
367  } else {
368  for (index = oldPosition; index > newPosition; index--) {
369  gerbvProject->file[index] = gerbvProject->file[index - 1];
370  }
371  }
372  gerbvProject->file[newPosition] = temp_file;
373 } /* gerbv_change_layer_order */
374 
375 /* ------------------------------------------------------------------ */
376 gint
377 gerbv_add_parsed_image_to_project(
378  gerbv_project_t* gerbvProject, gerbv_image_t* parsed_image, const gchar* filename, const gchar* baseName, int idx,
379  int reload
380 ) {
381  gerb_verify_error_t error = GERB_IMAGE_OK;
382  int r, g, b;
383 
384  dprintf("In open_image, now error check file....\n");
385  error = gerbv_image_verify(parsed_image);
386 
387  if (error) {
388  if (error & GERB_IMAGE_MISSING_NETLIST) {
389  GERB_COMPILE_ERROR(_("Missing netlist - aborting file read"));
390  gerbv_destroy_image(parsed_image);
391  return -1;
392  }
393  /* if the error was one of the following, try to open up the file anyways in case
394  the file is a poorly formatted RS-274X file */
395  if (error & GERB_IMAGE_MISSING_FORMAT)
396  g_warning(_("Missing format in file...trying to load anyways\n"));
397  if (error & GERB_IMAGE_MISSING_APERTURES) {
398  g_warning(_("Missing apertures/drill sizes...trying to load anyways\n"));
399  /* step through the file and check for aperture references. For each one found, create
400  a dummy aperture holder to visually draw something on the screen */
402  }
403  if (error & GERB_IMAGE_MISSING_INFO)
404  g_warning(_("Missing info...trying to load anyways\n"));
405  }
406 
407  /*
408  * If reload, just exchange the image. Else we have to allocate
409  * a new memory before we define anything more.
410  */
411  if (reload) {
412  gerbv_destroy_image(gerbvProject->file[idx]->image);
413  gerbvProject->file[idx]->image = parsed_image;
414  return 0;
415  } else {
416  /* Load new file. */
417  gerbvProject->file[idx] = (gerbv_fileinfo_t*)g_new0(gerbv_fileinfo_t, 1);
418  gerbvProject->file[idx]->image = parsed_image;
419  }
420 
421  /*
422  * Store filename for eventual reload
423  */
424  gerbvProject->file[idx]->fullPathname = g_strdup(filename);
425  gerbvProject->file[idx]->name = g_strdup(baseName);
426 
427  r = defaultColors[defaultColorIndex % NUMBER_OF_DEFAULT_COLORS].red * 257;
428  g = defaultColors[defaultColorIndex % NUMBER_OF_DEFAULT_COLORS].green * 257;
429  b = defaultColors[defaultColorIndex % NUMBER_OF_DEFAULT_COLORS].blue * 257;
430 
431  GdkColor colorTemplate = { 0, r, g, b };
432  gerbvProject->file[idx]->color = colorTemplate;
433  gerbvProject->file[idx]->alpha = defaultColors[defaultColorIndex % NUMBER_OF_DEFAULT_COLORS].alpha * 257;
434  gerbvProject->file[idx]->isVisible = TRUE;
435  gerbvProject->file[idx]->transform = defaultTransformations[defaultColorIndex % NUMBER_OF_DEFAULT_TRANSFORMATIONS];
436  /* update the number of files if we need to */
437  if (gerbvProject->last_loaded <= idx) {
438  gerbvProject->last_loaded = idx;
439  }
440  defaultColorIndex++;
441  return 1;
442 }
443 
444 /* ------------------------------------------------------------------ */
445 int
446 gerbv_open_image(
447  gerbv_project_t* gerbvProject, const gchar* filename, int idx, int reload, gerbv_HID_Attribute* fattr, int n_fattr,
448  gboolean forceLoadFile
449 ) {
450  gerb_file_t* fd;
451  gerbv_image_t * parsed_image = NULL, *parsed_image2 = NULL;
452  gint retv = -1;
453  gboolean isPnpFile = FALSE, foundBinary;
454  gerbv_HID_Attribute* attr_list = NULL;
455  int n_attr = 0;
456  /* If we're reloading, we'll pass in our file format attribute list
457  * since this is our hook for letting the user override the fileformat.
458  */
459  if (reload) {
460  /* We're reloading so use the attribute list in memory */
461  attr_list = gerbvProject->file[idx]->image->info->attr_list;
462  n_attr = gerbvProject->file[idx]->image->info->n_attr;
463  } else {
464  /* We're not reloading so use the attribute list read from the
465  * project file if given or NULL otherwise.
466  */
467  attr_list = fattr;
468  n_attr = n_fattr;
469  }
470  /* if we don't have enough spots, then grow the file list by 2 to account for the possible
471  loading of two images for PNP files */
472  if ((idx + 1) >= gerbvProject->max_files) {
473  gerbvProject->file = g_renew(gerbv_fileinfo_t*, gerbvProject->file, gerbvProject->max_files + 2);
474 
475  gerbvProject->file[gerbvProject->max_files] = NULL;
476  gerbvProject->file[gerbvProject->max_files + 1] = NULL;
477  gerbvProject->max_files += 2;
478  }
479 
480  dprintf("In open_image, about to try opening filename = %s\n", filename);
481 
482  fd = gerb_fopen(filename);
483  if (fd == NULL) {
484  GERB_COMPILE_ERROR(_("Trying to open \"%s\": %s"), filename, strerror(errno));
485  return -1;
486  }
487 
488  dprintf("In open_image, successfully opened file. Now check its type....\n");
489  /* Here's where we decide what file type we have */
490  /* Note: if the file has some invalid characters in it but still appears to
491  be a valid file, we check with the user if he wants to continue (only
492  if user opens the layer from the menu...if from the command line, we go
493  ahead and try to load it anyways) */
494 
495  if (gerber_is_rs274x_p(fd, &foundBinary)) {
496  dprintf("Found RS-274X file\n");
497  if (!foundBinary || forceLoadFile) {
498  /* figure out the directory path in case parse_gerb needs to
499  * load any include files */
500  gchar* currentLoadDirectory = g_path_get_dirname(filename);
501  parsed_image = parse_gerb(fd, currentLoadDirectory);
502  g_free(currentLoadDirectory);
503  }
504  } else if (drill_file_p(fd, &foundBinary)) {
505  dprintf("Found drill file\n");
506  if (!foundBinary || forceLoadFile)
507  parsed_image = parse_drillfile(fd, attr_list, n_attr, reload);
508 
509  } else if (pick_and_place_check_file_type(fd, &foundBinary)) {
510  dprintf("Found pick-n-place file\n");
511  if (!foundBinary || forceLoadFile) {
512  if (!reload) {
513  pick_and_place_parse_file_to_images(fd, &parsed_image, &parsed_image2);
514  } else {
515  switch (gerbvProject->file[idx]->image->layertype) {
517  /* Non NULL pointer is used as "not to reload" mark */
518  parsed_image2 = (void*)!NULL;
519  pick_and_place_parse_file_to_images(fd, &parsed_image, &parsed_image2);
520  parsed_image2 = NULL;
521  break;
523  /* Non NULL pointer is used as "not to reload" mark */
524  parsed_image2 = (void*)!NULL;
525  pick_and_place_parse_file_to_images(fd, &parsed_image2, &parsed_image);
526  parsed_image2 = NULL;
527  break;
528  default: GERB_COMPILE_ERROR(_("%s: unknown pick-and-place board side to reload"), filename);
529  }
530  }
531 
532  isPnpFile = TRUE;
533  }
534  } else if (gerber_is_rs274d_p(fd)) {
535  gchar* str = g_strdup_printf(
536  _("Most likely found a RS-274D file "
537  "\"%s\" ... trying to open anyways\n"),
538  filename
539  );
540  dprintf("%s", str);
541  g_warning("%s", str);
542  g_free(str);
543 
544  if (!foundBinary || forceLoadFile) {
545  /* figure out the directory path in case parse_gerb needs to
546  * load any include files */
547  gchar* currentLoadDirectory = g_path_get_dirname(filename);
548  parsed_image = parse_gerb(fd, currentLoadDirectory);
549  g_free(currentLoadDirectory);
550  }
551  } else {
552  /* This is not a known file */
553  dprintf("Unknown filetype");
554  GERB_COMPILE_ERROR(_("%s: Unknown file type."), filename);
555  parsed_image = NULL;
556  }
557 
558  gerb_fclose(fd);
559  if (parsed_image == NULL) {
560  return -1;
561  }
562 
563  if (parsed_image) {
564  /* strip the filename to the base */
565  gchar* baseName = g_path_get_basename(filename);
566  gchar* displayedName;
567  if (isPnpFile)
568  displayedName = g_strconcat(baseName, _(" (top)"), NULL);
569  else
570  displayedName = g_strdup(baseName);
571  retv = gerbv_add_parsed_image_to_project(gerbvProject, parsed_image, filename, displayedName, idx, reload);
572  g_free(baseName);
573  g_free(displayedName);
574  }
575 
576  /* Set layer_dirty flag to FALSE */
577  gerbvProject->file[idx]->layer_dirty = FALSE;
578 
579  /* for PNP place files, we may need to add a second image for the other
580  board side */
581  if (parsed_image2) {
582  /* strip the filename to the base */
583  gchar* baseName = g_path_get_basename(filename);
584  gchar* displayedName;
585  displayedName = g_strconcat(baseName, _(" (bottom)"), NULL);
586  retv = gerbv_add_parsed_image_to_project(gerbvProject, parsed_image2, filename, displayedName, idx + 1, reload);
587  g_free(baseName);
588  g_free(displayedName);
589  }
590 
591  return retv;
592 } /* open_image */
593 
596  gerbv_image_t* returnImage;
597  gerb_file_t* fd;
598 
599  fd = gerb_fopen(filename);
600  if (fd == NULL) {
601  GERB_COMPILE_ERROR(_("Trying to open \"%s\": %s"), filename, strerror(errno));
602  return NULL;
603  }
604  gchar* currentLoadDirectory = g_path_get_dirname(filename);
605  returnImage = parse_gerb(fd, currentLoadDirectory);
606  g_free(currentLoadDirectory);
607  gerb_fclose(fd);
608  return returnImage;
609 }
610 
611 static inline int
612 isnormal_or_zero(double x) {
613  int cl = fpclassify(x);
614  return cl == FP_NORMAL || cl == FP_ZERO;
615 }
616 
617 /* ------------------------------------------------------------------ */
618 void
619 gerbv_render_get_boundingbox(gerbv_project_t* gerbvProject, gerbv_render_size_t* boundingbox) {
620  double x1 = HUGE_VAL, y1 = HUGE_VAL, x2 = -HUGE_VAL, y2 = -HUGE_VAL;
621  int i;
622  gerbv_image_info_t* info;
623  gdouble minX, minY, maxX, maxY;
624 
625  for (i = 0; i <= gerbvProject->last_loaded; i++) {
626  if (gerbvProject->file[i] && gerbvProject->file[i]->isVisible) {
627 
628  info = gerbvProject->file[i]->image->info;
629  /*
630  * Find the biggest image and use as a size reference
631  */
632  /* cairo info already has offset calculated into min/max */
633 
634  minX = info->min_x;
635  minY = info->min_y;
636  maxX = info->max_x;
637  maxY = info->max_y;
638 
639  if (!isnormal_or_zero(minX) || !isnormal_or_zero(minY) || !isnormal_or_zero(maxX)
640  || !isnormal_or_zero(maxY)) {
641  continue;
642  }
643 
644  /* transform the bounding box based on the user transform */
645  cairo_matrix_t fullMatrix;
646  cairo_matrix_init(&fullMatrix, 1, 0, 0, 1, 0, 0);
647 
648  cairo_matrix_translate(
649  &fullMatrix, gerbvProject->file[i]->transform.translateX, gerbvProject->file[i]->transform.translateY
650  );
651  // don't use mirroring for the scale matrix
652  gdouble scaleX = gerbvProject->file[i]->transform.scaleX;
653  gdouble scaleY = gerbvProject->file[i]->transform.scaleY;
654  if (gerbvProject->file[i]->transform.mirrorAroundX)
655  scaleY *= -1;
656  if (gerbvProject->file[i]->transform.mirrorAroundY)
657  scaleX *= -1;
658  cairo_matrix_scale(&fullMatrix, scaleX, scaleY);
659  cairo_matrix_rotate(&fullMatrix, gerbvProject->file[i]->transform.rotation);
660 
661  cairo_matrix_transform_point(&fullMatrix, &minX, &minY);
662  cairo_matrix_transform_point(&fullMatrix, &maxX, &maxY);
663  /* compare to both min and max, since a mirror transform may have made the "max"
664  number smaller than the "min" */
665  x1 = MIN(x1, minX);
666  x1 = MIN(x1, maxX);
667  y1 = MIN(y1, minY);
668  y1 = MIN(y1, maxY);
669  x2 = MAX(x2, minX);
670  x2 = MAX(x2, maxX);
671  y2 = MAX(y2, minY);
672  y2 = MAX(y2, maxY);
673  }
674  }
675  boundingbox->left = x1;
676  boundingbox->right = x2;
677  boundingbox->top = y1;
678  boundingbox->bottom = y2;
679 }
680 
681 /* ------------------------------------------------------------------ */
682 void
685  double width, height;
686  double x_scale, y_scale;
687 
688  /* Grab maximal width and height of all layers */
689  gerbv_render_get_boundingbox(gerbvProject, &bb);
690  width = bb.right - bb.left;
691  height = bb.bottom - bb.top;
692  /* add in a 5% buffer around the drawing */
693  width *= 1.05;
694  height *= 1.05;
695 
696  /* if the values aren't sane (probably we have no models loaded), then
697  put in some defaults */
698  if (!isnormal(width) || !isnormal(height) || ((width < 0.01) && (height < 0.01))) {
699  renderInfo->lowerLeftX = 0.0;
700  renderInfo->lowerLeftY = 0.0;
701  renderInfo->scaleFactorX = 200;
702  renderInfo->scaleFactorY = renderInfo->scaleFactorX;
703  return;
704  }
705  /*
706  * Calculate scale for both x axis and y axis
707  */
708  x_scale = renderInfo->displayWidth / width;
709  y_scale = renderInfo->displayHeight / height;
710  /*
711  * Take the scale that fits both directions with some extra checks
712  */
713  renderInfo->scaleFactorX = MIN(x_scale, y_scale);
714  renderInfo->scaleFactorX = MIN((gdouble)GERBV_SCALE_MAX, renderInfo->scaleFactorX);
715  renderInfo->scaleFactorX = MAX((gdouble)GERBV_SCALE_MIN, renderInfo->scaleFactorX);
716  renderInfo->scaleFactorY = renderInfo->scaleFactorX;
717  renderInfo->lowerLeftX =
718  ((bb.left + bb.right) / 2.0) - ((double)renderInfo->displayWidth / 2.0 / renderInfo->scaleFactorX);
719  renderInfo->lowerLeftY =
720  ((bb.top + bb.bottom) / 2.0) - ((double)renderInfo->displayHeight / 2.0 / renderInfo->scaleFactorY);
721 }
722 
723 /* ------------------------------------------------------------------ */
724 void
725 gerbv_render_translate_to_fit_display(gerbv_project_t* gerbvProject, gerbv_render_info_t* renderInfo) {
727 
728  /* Grab maximal width and height of all layers */
729  gerbv_render_get_boundingbox(gerbvProject, &bb);
730  renderInfo->lowerLeftX =
731  ((bb.left + bb.right) / 2.0) - ((double)renderInfo->displayWidth / 2.0 / renderInfo->scaleFactorX);
732  renderInfo->lowerLeftY =
733  ((bb.top + bb.bottom) / 2.0) - ((double)renderInfo->displayHeight / 2.0 / renderInfo->scaleFactorY);
734 }
735 
736 /* ------------------------------------------------------------------ */
737 void
738 gerbv_render_to_pixmap_using_gdk(
739  gerbv_project_t* gerbvProject, GdkPixmap* pixmap, gerbv_render_info_t* renderInfo,
740  gerbv_selection_info_t* selectionInfo, GdkColor* selectionColor
741 ) {
742  GdkGC* gc = gdk_gc_new(pixmap);
743  GdkPixmap *colorStamp, *clipmask;
744  int i;
745 
746  /*
747  * Remove old pixmap, allocate a new one, draw the background.
748  */
749  if (!gerbvProject->background.pixel)
750  gdk_colormap_alloc_color(gdk_colormap_get_system(), &gerbvProject->background, FALSE, TRUE);
751  gdk_gc_set_foreground(gc, &gerbvProject->background);
752  gdk_draw_rectangle(pixmap, gc, TRUE, 0, 0, -1, -1);
753 
754  /*
755  * Allocate the pixmap and the clipmask (a one pixel pixmap)
756  */
757  colorStamp = gdk_pixmap_new(pixmap, renderInfo->displayWidth, renderInfo->displayHeight, -1);
758  clipmask = gdk_pixmap_new(NULL, renderInfo->displayWidth, renderInfo->displayHeight, 1);
759 
760  /*
761  * This now allows drawing several layers on top of each other.
762  * Higher layer numbers have higher priority in the Z-order.
763  */
764  for (i = gerbvProject->last_loaded; i >= 0; i--) {
765  if (gerbvProject->file[i] && gerbvProject->file[i]->isVisible) {
766  /*
767  * Fill up image with all the foreground color. Excess pixels
768  * will be removed by clipmask.
769  */
770  if (!gerbvProject->file[i]->color.pixel)
771  gdk_colormap_alloc_color(gdk_colormap_get_system(), &gerbvProject->file[i]->color, FALSE, TRUE);
772  gdk_gc_set_foreground(gc, &gerbvProject->file[i]->color);
773 
774  /* switch back to regular draw function for the initial
775  bitmap clear */
776  gdk_gc_set_function(gc, GDK_COPY);
777  gdk_draw_rectangle(colorStamp, gc, TRUE, 0, 0, -1, -1);
778 
779  if (renderInfo->renderType == GERBV_RENDER_TYPE_GDK) {
780  gdk_gc_set_function(gc, GDK_COPY);
781  } else if (renderInfo->renderType == GERBV_RENDER_TYPE_GDK_XOR) {
782  gdk_gc_set_function(gc, GDK_XOR);
783  }
784  /*
785  * Translation is to get it inside the allocated pixmap,
786  * which is not always centered perfectly for GTK/X.
787  */
788  dprintf(" .... calling image2pixmap on image %d...\n", i);
789  // Dirty scaling solution when using GDK; simply use scaling factor for x-axis, ignore y-axis
790  draw_gdk_image_to_pixmap(
791  &clipmask, gerbvProject->file[i]->image, renderInfo->scaleFactorX,
792  -(renderInfo->lowerLeftX * renderInfo->scaleFactorX),
793  (renderInfo->lowerLeftY * renderInfo->scaleFactorY) + renderInfo->displayHeight, DRAW_IMAGE, NULL,
794  renderInfo, gerbvProject->file[i]->transform
795  );
796 
797  /*
798  * Set clipmask and draw the clipped out image onto the
799  * screen pixmap. Afterwards we remove the clipmask, else
800  * it will screw things up when run this loop again.
801  */
802  gdk_gc_set_clip_mask(gc, clipmask);
803  gdk_gc_set_clip_origin(gc, 0, 0);
804  gdk_draw_drawable(pixmap, gc, colorStamp, 0, 0, 0, 0, -1, -1);
805  gdk_gc_set_clip_mask(gc, NULL);
806  }
807  }
808 
809  /* Render the selection group to the top of the output */
810  if (selectionInfo && selectionInfo->selectedNodeArray && (selection_length(selectionInfo) != 0)) {
811  if (!selectionColor->pixel)
812  gdk_colormap_alloc_color(gdk_colormap_get_system(), selectionColor, FALSE, TRUE);
813 
814  gdk_gc_set_foreground(gc, selectionColor);
815  gdk_gc_set_function(gc, GDK_COPY);
816  gdk_draw_rectangle(colorStamp, gc, TRUE, 0, 0, -1, -1);
817 
818  gerbv_selection_item_t sItem;
819  gerbv_fileinfo_t* file;
820  int j;
821  guint k;
822 
823  for (j = gerbvProject->last_loaded; j >= 0; j--) {
824  file = gerbvProject->file[j];
825  if (!file || (!gerbvProject->show_invisible_selection && !file->isVisible))
826  continue;
827 
828  for (k = 0; k < selection_length(selectionInfo); k++) {
829  sItem = selection_get_item_by_index(selectionInfo, k);
830 
831  if (file->image != sItem.image)
832  continue;
833 
834  /* Have selected image(s) on this layer, draw it */
835  draw_gdk_image_to_pixmap(
836  &clipmask, file->image, renderInfo->scaleFactorX,
837  -(renderInfo->lowerLeftX * renderInfo->scaleFactorX),
838  (renderInfo->lowerLeftY * renderInfo->scaleFactorY) + renderInfo->displayHeight, DRAW_SELECTIONS,
839  selectionInfo, renderInfo, file->transform
840  );
841 
842  gdk_gc_set_clip_mask(gc, clipmask);
843  gdk_gc_set_clip_origin(gc, 0, 0);
844  gdk_draw_drawable(pixmap, gc, colorStamp, 0, 0, 0, 0, -1, -1);
845  gdk_gc_set_clip_mask(gc, NULL);
846 
847  break;
848  }
849  }
850  }
851 
852  gdk_pixmap_unref(colorStamp);
853  gdk_pixmap_unref(clipmask);
854  gdk_gc_unref(gc);
855 }
856 
857 /* ------------------------------------------------------------------ */
858 void
859 gerbv_render_all_layers_to_cairo_target_for_vector_output(
860  gerbv_project_t* gerbvProject, cairo_t* cr, gerbv_render_info_t* renderInfo
861 ) {
862  GdkColor* bg = &gerbvProject->background;
863  int i;
864  double r, g, b;
865 
866  gerbv_render_cairo_set_scale_and_translation(cr, renderInfo);
867 
868  /* Fill the background with the appropriate not white and not black
869  * color for backward culpability. */
870  if ((bg->red != 0xffff || bg->green != 0xffff || bg->blue != 0xffff)
871  && (bg->red != 0x0000 || bg->green != 0x0000 || bg->blue != 0x0000)) {
872  r = (double)bg->red / G_MAXUINT16;
873  g = (double)bg->green / G_MAXUINT16;
874  b = (double)bg->blue / G_MAXUINT16;
875  cairo_set_source_rgba(cr, r, g, b, 1);
876  cairo_paint(cr);
877 
878  /* Set cairo user data with background color information, to be
879  * used for clear color. */
880  cairo_set_user_data(cr, (cairo_user_data_key_t*)0, &r, NULL);
881  cairo_set_user_data(cr, (cairo_user_data_key_t*)1, &g, NULL);
882  cairo_set_user_data(cr, (cairo_user_data_key_t*)2, &b, NULL);
883  }
884 
885  for (i = gerbvProject->last_loaded; i >= 0; i--) {
886  if (gerbvProject->file[i] && gerbvProject->file[i]->isVisible) {
887  gerbv_render_layer_to_cairo_target_without_transforming(cr, gerbvProject->file[i], renderInfo, FALSE);
888  }
889  }
890 }
891 
892 /* ------------------------------------------------------------------ */
893 void
894 gerbv_render_all_layers_to_cairo_target(gerbv_project_t* gerbvProject, cairo_t* cr, gerbv_render_info_t* renderInfo) {
895  int i;
896 
897  /* Fill the background with the appropriate color. */
898  cairo_set_source_rgba(
899  cr, (double)gerbvProject->background.red / G_MAXUINT16, (double)gerbvProject->background.green / G_MAXUINT16,
900  (double)gerbvProject->background.blue / G_MAXUINT16, 1
901  );
902  cairo_paint(cr);
903 
904  for (i = gerbvProject->last_loaded; i >= 0; i--) {
905  if (gerbvProject->file[i] && gerbvProject->file[i]->isVisible) {
906  cairo_push_group(cr);
907  gerbv_render_layer_to_cairo_target(cr, gerbvProject->file[i], renderInfo);
908  cairo_pop_group_to_source(cr);
909  cairo_paint_with_alpha(cr, (double)gerbvProject->file[i]->alpha / G_MAXUINT16);
910  }
911  }
912 }
913 
914 /* ------------------------------------------------------------------ */
915 void
917  gerbv_render_cairo_set_scale_and_translation(cr, renderInfo);
918  gerbv_render_layer_to_cairo_target_without_transforming(cr, fileInfo, renderInfo, TRUE);
919 }
920 
921 /* ------------------------------------------------------------------ */
922 void
923 gerbv_render_cairo_set_scale_and_translation(cairo_t* cr, gerbv_render_info_t* renderInfo) {
924  gdouble translateX, translateY;
925 
926  translateX = (renderInfo->lowerLeftX * renderInfo->scaleFactorX);
927  translateY = (renderInfo->lowerLeftY * renderInfo->scaleFactorY);
928 
929  /* renderTypes 0 and 1 use GDK rendering, so we shouldn't have made it
930  this far */
931  if (renderInfo->renderType == GERBV_RENDER_TYPE_CAIRO_NORMAL) {
932  cairo_set_tolerance(cr, 1.0);
933  cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
934  } else if (renderInfo->renderType == GERBV_RENDER_TYPE_CAIRO_HIGH_QUALITY) {
935  cairo_set_tolerance(cr, 0.1);
936  cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
937  }
938 
939  /* translate the draw area before drawing. We must translate the whole
940  drawing down an additional displayHeight to account for the negative
941  y flip done later */
942  cairo_translate(cr, -translateX, translateY + renderInfo->displayHeight);
943  /* scale the drawing by the specified scale factor (inverting y since
944  cairo y axis points down) */
945  cairo_scale(cr, renderInfo->scaleFactorX, -renderInfo->scaleFactorY);
946 }
947 
948 /* ------------------------------------------------------------------ */
949 void
950 gerbv_render_layer_to_cairo_target_without_transforming(
951  cairo_t* cr, gerbv_fileinfo_t* fileInfo, gerbv_render_info_t* renderInfo, gboolean pixelOutput
952 ) {
953  cairo_set_source_rgba(
954  cr, (double)fileInfo->color.red / G_MAXUINT16, (double)fileInfo->color.green / G_MAXUINT16,
955  (double)fileInfo->color.blue / G_MAXUINT16, 1
956  );
957 
958  /* translate, rotate, and modify the image based on the layer-specific transformation struct */
959  cairo_save(cr);
960 
961  draw_image_to_cairo_target(
962  cr, fileInfo->image, 1.0 / MAX(renderInfo->scaleFactorX, renderInfo->scaleFactorY), DRAW_IMAGE, NULL,
963  renderInfo, TRUE, fileInfo->transform, pixelOutput
964  );
965  cairo_restore(cr);
966 }
967 
968 void
969 gerbv_attribute_destroy_HID_attribute(gerbv_HID_Attribute* attributeList, int n_attr) {
970  int i;
971 
972  /* free the string attributes */
973  for (i = 0; i < n_attr; i++) {
974  if ((attributeList[i].type == HID_String || attributeList[i].type == HID_Label)
975  && attributeList[i].default_val.str_value != NULL) {
976  free(attributeList[i].default_val.str_value);
977  }
978  }
979 
980  /* and free the attribute list */
981  if (attributeList != NULL) {
982  free(attributeList);
983  }
984 }
985 
986 /* allocate memory and make a copy of an attribute list */
987 gerbv_HID_Attribute*
988 gerbv_attribute_dup(gerbv_HID_Attribute* attributeList, int n_attr) {
989  gerbv_HID_Attribute* nl;
990  int i;
991 
992  nl = (gerbv_HID_Attribute*)malloc(n_attr * sizeof(gerbv_HID_Attribute));
993  if (nl == NULL) {
994  fprintf(stderr, "malloc failed in %s()\n", __FUNCTION__);
995  exit(1);
996  }
997 
998  /* copy the attribute list being sure to strdup the strings */
999  for (i = 0; i < n_attr; i++) {
1000 
1001  if (attributeList[i].type == HID_String || attributeList[i].type == HID_Label) {
1002 
1003  if (attributeList[i].default_val.str_value != NULL) {
1004  nl[i].default_val.str_value = strdup(attributeList[i].default_val.str_value);
1005  } else {
1006  nl[i].default_val.str_value = NULL;
1007  }
1008 
1009  } else {
1010  nl[i] = attributeList[i];
1011  }
1012  }
1013 
1014  return nl;
1015 }
1016 
1019  int i;
1020 
1021  for (i = 0; i <= project->last_loaded; i++) {
1022  if (project->file[i]->image == image)
1023  return project->file[i];
1024  }
1025 
1026  return NULL;
1027 }
1028 
1029 inline void
1030 gerbv_rotate_coord(double* x, double* y, double rad) {
1031  double x0 = *x;
1032 
1033  *x = x0 * cos(rad) - *y * sin(rad);
1034  *y = x0 * sin(rad) + *y * cos(rad);
1035 }
1036 
1037 void
1038 gerbv_transform_coord(double* x, double* y, const gerbv_user_transformation_t* trans) {
1039 
1040  *x = trans->scaleX * *x;
1041  *y = trans->scaleY * *y;
1042 
1043  gerbv_rotate_coord(x, y, trans->rotation);
1044 
1045  if (trans->mirrorAroundY)
1046  *x = -*x;
1047 
1048  if (trans->mirrorAroundX)
1049  *y = -*y;
1050 
1051  *x += trans->translateX;
1052  *y += trans->translateY;
1053 }
1054 
1055 int
1056 gerbv_transform_coord_for_image(double* x, double* y, const gerbv_image_t* image, const gerbv_project_t* project) {
1057  gerbv_fileinfo_t* fileinfo = gerbv_get_fileinfo_for_image(image, project);
1058 
1059  if (fileinfo == NULL) {
1060  dprintf("%s(): NULL fileinfo\n", __func__);
1061  return -1;
1062  }
1063 
1064  gerbv_transform_coord(x, y, &fileinfo->transform);
1065 
1066  return 0;
1067 }
1068 
1069 gboolean
1070 gerbv_endswith(const char* path, const char* ext) {
1071  int plen = strlen(path);
1072  int elen = strlen(ext);
1073  if (plen < elen)
1074  return FALSE; // false if string too short to check
1075  return (strcmp(path + plen - elen, ext) == 0) ? TRUE // true if last chars match extension
1076  : FALSE;
1077 }
Contains basic defines.
Header info for the GDK rendering functions.
Header info for the cairo rendering functions and the related selection calculating functions.
Header info for the Excellon drill parsing functions.
gboolean gerbv_export_drill_file_from_image(const gchar *filename, gerbv_image_t *inputImage, gerbv_user_transformation_t *transform)
Export an image to a new file in Excellon drill format.
Definition: export-drill.c:43
gboolean gerbv_export_rs274x_file_from_image(const gchar *filename, gerbv_image_t *inputImage, gerbv_user_transformation_t *transform)
Export an image to a new file in RS274X format.
void gerbv_destroy_image(gerbv_image_t *image)
Free an image structure.
Definition: gerb_image.c:104
void gerbv_image_create_dummy_apertures(gerbv_image_t *parsed_image)
Create any missing apertures in the specified image.
Definition: gerb_image.c:1276
gboolean gerber_is_rs274d_p(gerb_file_t *fd)
Definition: gerber.c:846
gboolean gerber_is_rs274x_p(gerb_file_t *fd, gboolean *returnFoundBinary)
Definition: gerber.c:756
gerbv_image_t * parse_gerb(gerb_file_t *fd, gchar *directoryPath)
Definition: gerber.c:692
Header info for the RS274X parsing functions.
void gerbv_open_layer_from_filename(gerbv_project_t *gerbvProject, const gchar *filename)
Open a file, parse the contents, and add a new layer to an existing project.
Definition: gerbv.c:214
void gerbv_destroy_project(gerbv_project_t *gerbvProject)
Free a project and all related variables.
Definition: gerbv.c:181
const char * gerbv_interpolation_name(gerbv_interpolation_t interp)
Return string name of gerbv_interpolation_t interpolation.
Definition: gerbv.c:97
void gerbv_rotate_coord(double *x, double *y, double rad)
Definition: gerbv.c:1030
gerbv_image_t * gerbv_create_rs274x_image_from_filename(const gchar *filename)
Parse a RS274X file and return the parsed image.
Definition: gerbv.c:595
gerbv_project_t * gerbv_create_project(void)
Create a new project structure and initialize some important variables.
Definition: gerbv.c:164
void gerbv_open_layer_from_filename_with_color(gerbv_project_t *gerbvProject, const gchar *filename, guint16 red, guint16 green, guint16 blue, guint16 alpha)
Open a file, parse the contents, and add a new layer to an existing project while setting the color o...
Definition: gerbv.c:230
gerbv_fileinfo_t * gerbv_get_fileinfo_for_image(const gerbv_image_t *image, const gerbv_project_t *project)
Definition: gerbv.c:1018
void gerbv_transform_coord(double *x, double *y, const gerbv_user_transformation_t *trans)
Definition: gerbv.c:1038
gboolean gerbv_endswith(const char *path, const char *ext)
Definition: gerbv.c:1070
void gerbv_destroy_fileinfo(gerbv_fileinfo_t *fileInfo)
Free a fileinfo structure.
Definition: gerbv.c:203
const char * gerbv_aperture_type_name(gerbv_aperture_type_t type)
Return string name of gerbv_aperture_type_t aperture type.
Definition: gerbv.c:72
void gerbv_render_zoom_to_fit_display(gerbv_project_t *gerbvProject, gerbv_render_info_t *renderInfo)
Calculate the zoom and translations to fit the rendered scene inside the given scene size.
Definition: gerbv.c:683
int gerbv_transform_coord_for_image(double *x, double *y, const gerbv_image_t *image, const gerbv_project_t *project)
Definition: gerbv.c:1056
void gerbv_render_layer_to_cairo_target(cairo_t *cr, gerbv_fileinfo_t *fileInfo, gerbv_render_info_t *renderInfo)
Render a layer to a cairo context.
Definition: gerbv.c:916
The main header file for the libgerbv library.
@ GERBV_RENDER_TYPE_CAIRO_HIGH_QUALITY
Definition: gerbv.h:371
@ GERBV_RENDER_TYPE_GDK_XOR
Definition: gerbv.h:369
@ GERBV_RENDER_TYPE_GDK
Definition: gerbv.h:368
@ GERBV_RENDER_TYPE_CAIRO_NORMAL
Definition: gerbv.h:370
gerbv_aperture_type_t
Definition: gerbv.h:150
gerbv_interpolation_t
Definition: gerbv.h:293
@ GERBV_LAYERTYPE_PICKANDPLACE_BOT
Definition: gerbv.h:326
@ GERBV_LAYERTYPE_RS274X
Definition: gerbv.h:323
@ GERBV_LAYERTYPE_PICKANDPLACE_TOP
Definition: gerbv.h:325
@ GERBV_LAYERTYPE_DRILL
Definition: gerbv.h:324
Header info for the PNP (pick-and-place) parsing functions.
Header info for the selection support functions for libgerbv.
guint16 alpha
Definition: gerbv.h:748
gchar * fullPathname
Definition: gerbv.h:751
gerbv_image_t * image
Definition: gerbv.h:746
gerbv_user_transformation_t transform
Definition: gerbv.h:754
gchar * name
Definition: gerbv.h:752
GdkColor color
Definition: gerbv.h:747
gboolean layer_dirty
Definition: gerbv.h:755
gpointer privateRenderData
Definition: gerbv.h:750
gboolean isVisible
Definition: gerbv.h:749
gerbv_layertype_t layertype
Definition: gerbv.h:732
gerbv_image_info_t * info
Definition: gerbv.h:738
gerbv_fileinfo_t ** file
Definition: gerbv.h:763
gchar * project
Definition: gerbv.h:772
gboolean show_invisible_selection
Definition: gerbv.h:768
GdkColor background
Definition: gerbv.h:761
gboolean check_before_delete
Definition: gerbv.h:767
gchar * execname
Definition: gerbv.h:771
gchar * path
Definition: gerbv.h:769
gchar * execpath
Definition: gerbv.h:770
int max_files
Definition: gerbv.h:762
int last_loaded
Definition: gerbv.h:765
gdouble lowerLeftY
Definition: gerbv.h:788
gdouble scaleFactorX
Definition: gerbv.h:785
gint displayHeight
Definition: gerbv.h:791
gdouble lowerLeftX
Definition: gerbv.h:787
gerbv_render_types_t renderType
Definition: gerbv.h:789
gdouble scaleFactorY
Definition: gerbv.h:786