gerbv
callbacks.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23 
29 #include "gerbv.h"
30 #include "drill.h"
31 
32 #if !defined(WIN32) && !defined(QUARTZ)
33 # include <gdk/gdkx.h>
34 #endif
35 
36 #ifdef HAVE_STDLIB_H
37 #include <stdlib.h>
38 #endif
39 
40 #ifdef HAVE_STRING_H
41 #include <string.h>
42 #endif
43 
44 #ifdef HAVE_TIME_H
45 #include <time.h>
46 #endif
47 
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51 
52 #include <math.h>
53 #include "common.h"
54 #include "main.h"
55 
56 #include "attribute.h"
57 #include "callbacks.h"
58 #include "interface.h"
59 #include "project.h"
60 #include "render.h"
61 #include "selection.h"
62 #include "table.h"
63 
64 #include "draw-gdk.h"
65 
66 #include "draw.h"
67 #ifdef WIN32
68 # include <cairo-win32.h>
69 #elif defined(QUARTZ)
70 # include <cairo-quartz.h>
71 #else
72 # include <cairo-xlib.h>
73 #endif
74 
75 
76 #undef DPRINTF
77 #define DPRINTF(...) do { if (DEBUG) printf(__VA_ARGS__); } while (0)
78 
79 /* This default extension should really not be changed, but if it absolutely
80  * must change, the ../win32/gerbv.nsi.in *must* be changed to reflect that.
81  * Just grep for the extension (gvp) and change it in two places in that file.
82  */
83 #define GERBV_PROJECT_FILE_EXT ".gvp"
84 const char *gerbv_project_file_name = N_("Gerbv Project");
85 const char *gerbv_project_file_pat = "*" GERBV_PROJECT_FILE_EXT;
86 
87 static gint callbacks_get_selected_row_index (void);
88 static void callbacks_units_changed (gerbv_gui_unit_t unit);
89 static void callbacks_update_statusbar_coordinates (gint x, gint y);
90 static void callbacks_update_ruler_scales (void);
91 static void callbacks_render_type_changed (void);
92 static void show_no_layers_warning (void);
93 
94 static double screen_units(double);
95 static const char *screen_units_str(void);
96 
97 static double line_length(double, double, double, double);
98 static double arc_length(double, double);
99 
100 static void aperture_state_report (gerbv_net_t *,
102 static void aperture_report(gerbv_aperture_t *[], int,
103  double, double, gerbv_image_t *, gerbv_project_t *);
104 static void drill_report(gerbv_aperture_t *[], int);
105 static void parea_report(gerbv_net_t *,
107 static void net_layer_file_report(gerbv_net_t *,
109 static void analyze_window_size_restore(GtkWidget *);
110 static void analyze_window_size_store(GtkWidget *, gpointer);
111 
112 static void update_selected_object_message (gboolean userTriedToSelect);
113 
114 
115 gchar *utf8_strncpy(gchar *dst, const gchar *src, gsize byte_len)
116 {
117  /* -1 for '\0' in buffer */
118  glong char_len = g_utf8_strlen(src, byte_len - 1);
119  return g_utf8_strncpy(dst, src, char_len);
120 }
121 
122 void utf8_snprintf(gchar *dst, gsize byte_len, const gchar *fmt, ...)
123 {
124  va_list ap;
125 
126  va_start(ap, fmt);
127  gchar *str = g_strdup_vprintf(fmt, ap);
128  va_end(ap);
129  utf8_strncpy(dst, str, byte_len);
130  g_free(str);
131 }
132 
133 /* --------------------------------------------------------- */
134 
135 static void show_no_layers_warning (void) {
136  gchar *str = g_new(gchar, MAX_DISTLEN);
137  utf8_strncpy(str, _("No layers are currently loaded. A layer must be loaded first."), MAX_DISTLEN - 7);
138  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN, "<b>%s</b>", str);
139  g_free(str);
140 
142 }
143 
144 /* --------------------------------------------------------- */
150 void
151 callbacks_new_project_activate (GtkMenuItem *menuitem, gpointer user_data)
152 {
153  if (mainProject->last_loaded >= 0) {
155  _("Do you want to close any open layers "
156  "and start a new project?"),
157  _("Starting a new project will cause all currently "
158  "open layers to be closed. Any unsaved changes "
159  "will be lost."),
160  FALSE, NULL, GTK_STOCK_CLOSE, GTK_STOCK_CANCEL))
161  return;
162  }
163  /* Unload all layers and then clear layer window */
164  gerbv_unload_all_layers (mainProject);
165  callbacks_update_layer_tree ();
166  selection_clear (&screen.selectionInfo);
167  update_selected_object_message (FALSE);
168 
169  /* Destroy project info */
170  if (mainProject->project) {
171  g_free(mainProject->project);
172  mainProject->project = NULL;
173  }
174  render_refresh_rendered_image_on_screen();
175 }
176 
177 
178 /* --------------------------------------------------------- */
184 void open_project(char *project_filename)
185 {
186 
187 /* TODO: check if layers is modified and show it to user. */
188 
189  if (mainProject->last_loaded >= 0
191  _("Do you want to close any open layers and load "
192  "an existing project?"),
193  _("Loading a project will cause all currently open "
194  "layers to be closed. Any unsaved changes "
195  "will be lost."),
196  FALSE, NULL, GTK_STOCK_CLOSE, GTK_STOCK_CANCEL)) {
197 
198  return;
199  }
200 
201  /* Update the last folder */
202  g_free (mainProject->path);
203  mainProject->path = g_strdup(project_filename);
204 
205  gerbv_unload_all_layers (mainProject);
206  main_open_project_from_filename (mainProject, project_filename);
207 }
208 
209 
210 /* --------------------------------------------------------- */
218 void open_files(GSList *filenames)
219 {
220  GSList *fns = NULL; /* File names to ask */
221  GSList *fns_is_mod = NULL; /* File name layer is modified */
222  GSList *fns_cnt = NULL; /* File names count */
223  GSList *fns_lay_num = NULL; /* Layer number for fns */
224  GSList *cnt = NULL; /* File names count unsorted by layers,
225  0 -- file not yet loaded as layer */
226  gint answer;
227 
228  if (filenames == NULL)
229  return;
230 
231  /* Check if there is a Gerbv project in the list.
232  * If there is least open only that and ignore the rest. */
233  for (GSList *fn = filenames; fn; fn = fn->next) {
234  gboolean is_project = FALSE;
235  if (0 == project_is_gerbv_project(fn->data, &is_project)
236  && is_project) {
237  open_project(fn->data);
238 
240  &screenRenderInfo);
241  render_refresh_rendered_image_on_screen();
242  callbacks_update_layer_tree();
243 
244  return;
245  }
246  }
247 
248  /* Count opened filenames and place result in list */
249  for (GSList *fn = filenames; fn; fn = fn->next) {
250  gint c = 0;
251 
252  for (gint fidx = 0; fidx <= mainProject->last_loaded; ++fidx) {
253  gchar *fpn = mainProject->file[fidx]->fullPathname;
254 
255  if (strlen(fpn) == strlen(fn->data)
256  && 0 == g_ascii_strncasecmp(fpn, fn->data,
257  strlen(fn->data))) {
258  c++;
259  }
260  }
261 
262  cnt = g_slist_append(cnt, GINT_TO_POINTER(c));
263  }
264 
265  /* Make fns, fns_is_mod and fns_cnt lists sorted by layers */
266  for (gint fidx = 0; fidx <= mainProject->last_loaded; ++fidx) {
267  gchar *fpn = mainProject->file[fidx]->fullPathname;
268 
269  for (GSList *fn = filenames; fn; fn = fn->next) {
270  if (strlen(fpn) == strlen(fn->data)
271  && 0 == g_ascii_strncasecmp(fpn, fn->data,
272  strlen(fn->data))) {
273  fns = g_slist_append(fns, fn->data);
274  fns_is_mod = g_slist_append(fns_is_mod,
275  GINT_TO_POINTER(mainProject->
276  file[fidx]->
277  layer_dirty));
278  fns_cnt = g_slist_append(fns_cnt,
279  g_slist_nth_data(cnt,
280  g_slist_position(
281  filenames,
282  fn)));
283  fns_lay_num = g_slist_append(fns_lay_num,
284  GINT_TO_POINTER(fidx));
285 
286  break;
287  }
288  }
289  }
290 
291  answer = GTK_RESPONSE_NONE;
292  if (g_slist_length(fns) > 0)
293  answer = interface_reopen_question(fns, fns_is_mod,
294  fns_cnt, fns_lay_num);
295 
296  switch (answer) {
297 
298  case GTK_RESPONSE_CANCEL:
299  case GTK_RESPONSE_NONE:
300  case GTK_RESPONSE_DELETE_EVENT:
301  /* Dialog is closed or Esc is pressed, skip all */
302  break;
303 
304  case GTK_RESPONSE_YES: /* Reload layer was selected */
305  for (GSList *fn = fns; fn; fn = fn->next) {
306  if (fn->data != NULL)
307  gerbv_revert_file(mainProject,
308  GPOINTER_TO_INT(
309  g_slist_nth_data (fns_lay_num,
310  g_slist_position (fns,
311  fn))));
312  }
313  break;
314 
315  case GTK_RESPONSE_OK: /* Open as a new layer was selected */
316  /* To open as new only _one_ instance of file, check filenames
317  * by selected files in fns */
318  for (GSList *fn = filenames; fn; fn = fn->next) {
319  if (NULL != g_slist_find (fns, fn->data))
321  fn->data);
322  }
323  break;
324  }
325 
326  /* Add not loaded files (cnt == 0) in the end */
327  for (GSList *fn = filenames; fn; fn = fn->next) {
328  if (0 == GPOINTER_TO_INT(g_slist_nth_data(cnt,
329  g_slist_position(filenames, fn))))
331  }
332 
333  g_slist_free(fns);
334  g_slist_free(fns_is_mod);
335  g_slist_free(fns_cnt);
336  g_slist_free(fns_lay_num);
337  g_slist_free(cnt);
338 
339  gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
340  render_refresh_rendered_image_on_screen();
341  callbacks_update_layer_tree();
342 }
343 
344 /* --------------------------------------------------------- */
350 void
351 callbacks_open_activate(GtkMenuItem *menuitem, gpointer user_data)
352 {
353  GSList *fns = NULL;
354  screen.win.gerber =
355  gtk_file_chooser_dialog_new (
356  _("Open Gerbv project, Gerber, drill, "
357  "or pick&place files"),
358  NULL, GTK_FILE_CHOOSER_ACTION_OPEN,
359  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
360  GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
361  NULL);
362 
363  gtk_file_chooser_set_select_multiple(
364  (GtkFileChooser *)screen.win.gerber, TRUE);
365  gtk_file_chooser_set_current_folder(
366  (GtkFileChooser *)screen.win.gerber, mainProject->path);
367  gtk_widget_show (screen.win.gerber);
368  if (gtk_dialog_run ((GtkDialog*)screen.win.gerber) ==
369  GTK_RESPONSE_ACCEPT) {
370  fns = gtk_file_chooser_get_filenames(
371  GTK_FILE_CHOOSER (screen.win.gerber));
372  /* Update the last folder */
373  g_free (mainProject->path);
374  mainProject->path = gtk_file_chooser_get_current_folder(
375  (GtkFileChooser *)screen.win.gerber);
376  }
377  gtk_widget_destroy (screen.win.gerber);
378 
379  open_files (fns);
380  g_slist_free_full (fns, g_free);
381 }
382 
383 /* --------------------------------------------------------- */
384 void
385 callbacks_revert_activate (GtkMenuItem *menuitem, gpointer user_data)
386 {
387  gerbv_revert_all_files (mainProject);
388  selection_clear (&screen.selectionInfo);
389  update_selected_object_message (FALSE);
390  render_refresh_rendered_image_on_screen ();
391  callbacks_update_layer_tree ();
392 }
393 
394 /* --------------------------------------------------------- */
395 void
396 callbacks_save_project_activate (GtkMenuItem *menuitem,
397  gpointer user_data)
398 {
399  if (mainProject->project)
400  main_save_project_from_filename (mainProject, mainProject->project);
401  else
402  callbacks_generic_save_activate (menuitem, (gpointer) CALLBACKS_SAVE_PROJECT_AS);
403  callbacks_update_layer_tree();
404  return;
405 }
406 
407 /* --------------------------------------------------------- */
408 void
409 callbacks_save_layer_activate (GtkMenuItem *menuitem,
410  gpointer user_data)
411 {
412  /* first figure out which layer in the layer side menu is selected */
414 
415  /* Now save that layer */
416  if (index >= 0) {
417  if (!gerbv_save_layer_from_index (mainProject, index, mainProject->file[index]->fullPathname)) {
418  interface_show_alert_dialog(_("Gerbv cannot export this file type"),
419  NULL,
420  FALSE,
421  NULL);
422  mainProject->file[index]->layer_dirty = FALSE;
423  callbacks_update_layer_tree();
424  return;
425  }
426  }
427  callbacks_update_layer_tree();
428  return;
429 }
430 struct l_image_info {
431  gerbv_image_t *image;
432  gerbv_user_transformation_t *transform;
433 };
434 
435 /* --------------------------------------------------------- */
440 {
441  gint i, filecount, img;
442  gerbv_image_t *out;
443  gerbv_layertype_t layertype;
444  struct l_image_info {
445  gerbv_image_t *image;
446  gerbv_user_transformation_t *transform;
447  } *images;
448 
449  images=(struct l_image_info *)g_new0(struct l_image_info,1);
450  out = NULL;
451  switch(type) {
452  case CALLBACKS_SAVE_FILE_DRILLM:
453  layertype = GERBV_LAYERTYPE_DRILL;
454  break;
455  case CALLBACKS_SAVE_FILE_RS274XM:
456  layertype = GERBV_LAYERTYPE_RS274X;
457  break;
458  default:
459  GERB_COMPILE_ERROR(_("Unknown Layer type for merge"));
460  goto err;
461  }
462  DPRINTF("Looking for matching files\n");
463  for (i = img = filecount = 0; i < mainProject->max_files; ++i) {
464  if (mainProject->file[i] && mainProject->file[i]->isVisible &&
465  (mainProject->file[i]->image->layertype == layertype)) {
466  ++filecount;
467  DPRINTF("Adding '%s'\n", mainProject->file[i]->name);
468  images[img].image=mainProject->file[i]->image;
469  images[img++].transform=&mainProject->file[i]->transform;
470  images = (struct l_image_info *)g_renew(struct l_image_info, images, img+1);
471  }
472  }
473  if (filecount < 2) {
474  GERB_COMPILE_ERROR(_("Not Enough Files of same type to merge"));
475  goto err;
476  }
477  DPRINTF("Now merging files\n");
478  for (i = 0; i < img; ++i) {
479  gerbv_user_transformation_t *thisTransform;
480  gerbv_user_transformation_t identityTransform = {0,0,1,1,0,FALSE,FALSE,FALSE};
481  thisTransform=images[i].transform;
482  if (NULL == thisTransform)
483  thisTransform = &identityTransform;
484  if (0 == i)
485  out = gerbv_image_duplicate_image(images[i].image, thisTransform);
486  else
487  gerbv_image_copy_image(images[i].image, thisTransform, out);
488  }
489 err:
490  g_free(images);
491  return out;
492 }
493 
494 /* --------------------------------------------------------- */
495 int
496 visible_file_name(gchar **file_name, gchar **dir_name,
497  gerbv_layertype_t layer_type, /* -1 for all types */
498  const gchar *file_extension,
499  const gchar *untitled_file_extension)
500 {
501  unsigned int count = 0;
502  gerbv_fileinfo_t *first_vis_file = NULL;
503 
504  for (int i = 0; i < mainProject->max_files; ++i) {
505  if (mainProject->file[i]
506  && mainProject->file[i]->isVisible
507  && (layer_type == (gerbv_layertype_t)-1
508  || layer_type == mainProject->file[i]->image->layertype)) {
509  if (first_vis_file == NULL) {
510  first_vis_file = mainProject->file[i];
511  /* Always directory of first visible file */
512  if (dir_name)
513  *dir_name = g_path_get_dirname (
514  first_vis_file->fullPathname);
515  }
516 
517  if (++count == 2 && file_name) {
518  *file_name = g_strdup_printf("%s%s",
519  pgettext("file name",
520  "untitled"),
521  untitled_file_extension);
522  }
523  }
524  }
525 
526  if (count == 1 && file_name)
527  *file_name = g_strdup_printf("%s%s",
528  first_vis_file->name, file_extension);
529 
530  return count;
531 }
532 
533 /* --------------------------------------------------------- */
534 void
535 callbacks_generic_save_activate (GtkMenuItem *menuitem,
536  gpointer user_data)
537 {
538  gchar *new_file_name = NULL;
539  gchar *file_name = NULL;
540  gchar *dir_name = NULL;
541  gboolean error_visible_layers = FALSE;
542  gchar *windowTitle = NULL;
543  gerbv_fileinfo_t *act_file;
544  gint file_index;
545  gint processType = GPOINTER_TO_INT (user_data);
546  GtkFileFilter *filter;
547  GtkSpinButton *spin_but;
548  GtkTooltips *tooltips;
549  GtkWidget *label;
550  GtkWidget *hbox;
551  GtkWidget *svg_layers_check;
552  GtkWidget *svg_cairo_check;
553  static gint dpi = 0;
554  static gboolean svg_layers = FALSE;
555 
556  file_index = callbacks_get_selected_row_index ();
557  if (file_index < 0) {
558  interface_show_alert_dialog (_("No layer is currently active"),
559  _("Please select a layer and try again."),
560  FALSE,
561  NULL);
562  return;
563  }
564 
565  act_file = mainProject->file[file_index];
566 
567  screen.win.gerber = gtk_file_chooser_dialog_new ("", NULL,
568  GTK_FILE_CHOOSER_ACTION_SAVE, NULL, NULL, NULL);
569  GtkFileChooser *file_chooser_p =
570  GTK_FILE_CHOOSER(screen.win.gerber);
571  gtk_file_chooser_set_do_overwrite_confirmation (file_chooser_p, TRUE);
572 
573  hbox = gtk_hbox_new (0, 0);
574  spin_but = GTK_SPIN_BUTTON(gtk_spin_button_new_with_range (0, 0, 1));
575  svg_layers_check = gtk_check_button_new_with_label (_("Export as Inkscape layers"));
576  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (svg_layers_check), svg_layers);
577  svg_cairo_check = gtk_check_button_new_with_label (_("Use Cairo SVG (legacy)"));
578  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (svg_cairo_check), mainProject->use_cairo_svg);
579  label = gtk_label_new ("");
580  tooltips = gtk_tooltips_new ();
581  gtk_box_pack_end (GTK_BOX(hbox), GTK_WIDGET(spin_but), 0, 0, 1);
582  gtk_box_pack_end (GTK_BOX(hbox), label, 0, 0, 5);
583  gtk_box_pack_end (GTK_BOX(GTK_DIALOG(screen.win.gerber)->vbox),
584  svg_cairo_check, 0, 0, 2);
585  gtk_box_pack_end (GTK_BOX(GTK_DIALOG(screen.win.gerber)->vbox),
586  svg_layers_check, 0, 0, 2);
587  gtk_box_pack_end (GTK_BOX(GTK_DIALOG(screen.win.gerber)->vbox),
588  hbox, 0, 0, 2);
589 
590  switch (processType) {
591  case CALLBACKS_SAVE_PROJECT_AS:
592  windowTitle = g_strdup (_("Save project as..."));
593  if (mainProject->project) {
594  file_name = g_path_get_basename (mainProject->project);
595 
596  dir_name = g_path_get_dirname (mainProject->project);
597  } else {
598  file_name = g_strdup_printf("%s%s",
599  pgettext("file name", "untitled"),
600  GERBV_PROJECT_FILE_EXT);
601  dir_name= g_path_get_dirname (act_file->fullPathname);
602  }
603 
604  filter = gtk_file_filter_new ();
605  gtk_file_filter_set_name (filter, _(gerbv_project_file_name));
606  gtk_file_filter_add_pattern (filter, gerbv_project_file_pat);
607  gtk_file_chooser_add_filter (file_chooser_p, filter);
608 
609  filter = gtk_file_filter_new ();
610  gtk_file_filter_set_name (filter, _("All"));
611  gtk_file_filter_add_pattern (filter, "*");
612  gtk_file_chooser_add_filter (file_chooser_p, filter);
613 
614  break;
615  case CALLBACKS_SAVE_FILE_PS:
616  windowTitle = g_strdup_printf (
617  _("Export visible layers to %s file as..."),
618  _("PS"));
619  if (0 == visible_file_name(&file_name, &dir_name, -1,
620  ".ps", ".ps")) {
621  error_visible_layers = TRUE;
622  break;
623  }
624 
625 
626  break;
627  case CALLBACKS_SAVE_FILE_PDF:
628  windowTitle = g_strdup_printf (
629  _("Export visible layers to %s file as..."),
630  _("PDF"));
631  if (0 == visible_file_name(&file_name, &dir_name, -1,
632  ".pdf", ".pdf")) {
633  error_visible_layers = TRUE;
634  break;
635  }
636 
637 
638  break;
639  case CALLBACKS_SAVE_FILE_SVG:
640  windowTitle = g_strdup_printf (
641  _("Export visible layers to %s file as..."),
642  _("SVG"));
643  if (0 == visible_file_name(&file_name, &dir_name, -1,
644  ".svg", ".svg")) {
645  error_visible_layers = TRUE;
646  break;
647  }
648 
649  gtk_tooltips_set_tip (tooltips, GTK_WIDGET(svg_layers_check),
650  _("Create one Inkscape layer per visible gerber layer"), NULL);
651  gtk_widget_show_all (svg_layers_check);
652 
653  gtk_tooltips_set_tip (tooltips, GTK_WIDGET(svg_cairo_check),
654  _("Use Cairo's SVG surface (larger files, legacy behavior)"), NULL);
655  gtk_widget_show_all (svg_cairo_check);
656 
657 
658  break;
659  case CALLBACKS_SAVE_FILE_DXF:
660  windowTitle = g_strdup_printf (
661  _("Export \"%s\" layer #%d to DXF file as..."),
662  act_file->name, file_index + 1);
663  file_name = g_strconcat (act_file->name, ".dxf", NULL);
664  dir_name = g_path_get_dirname (act_file->fullPathname);
665  break;
666  case CALLBACKS_SAVE_FILE_PNG:
667  windowTitle = g_strdup_printf (
668  _("Export visible layers to %s file as..."),
669  _("PNG"));
670  if (0 == visible_file_name(&file_name, &dir_name, -1,
671  ".png", ".png")) {
672  error_visible_layers = TRUE;
673  break;
674  }
675 
676  gtk_label_set_text (GTK_LABEL(label), _("DPI:"));
677  gtk_spin_button_set_range (spin_but, 0, 6000);
678  gtk_spin_button_set_increments (spin_but, 10, 100);
679  gtk_tooltips_set_tip (tooltips, GTK_WIDGET(label),
680  _("DPI value, autoscaling if 0"), NULL);
681  gtk_tooltips_set_tip (tooltips, GTK_WIDGET(spin_but),
682  _("DPI value, autoscaling if 0"), NULL);
683  gtk_spin_button_set_value (spin_but, dpi);
684  gtk_widget_show_all (hbox);
685 
686  break;
687  case CALLBACKS_SAVE_FILE_RS274X:
688  windowTitle = g_strdup_printf(
689  _("Export \"%s\" layer #%d to "
690  "RS-274X file as..."),
691  act_file->name, file_index+1);
692 
693  if (GERBV_LAYERTYPE_RS274X != act_file->image->layertype)
694  file_name = g_strconcat (act_file->name, ".gbr", NULL);
695  else
696  file_name = g_strdup (act_file->name);
697 
698  dir_name = g_path_get_dirname (act_file->fullPathname);
699  break;
700  case CALLBACKS_SAVE_FILE_RS274XM:
701  windowTitle = g_strdup (_("Export merged visible layers to "
702  "RS-274X file as..."));
703  if (2 > visible_file_name(&file_name, &dir_name,
704  GERBV_LAYERTYPE_RS274X, "", ".gbr")) {
705  error_visible_layers = TRUE;
706  break;
707  }
708  break;
709  case CALLBACKS_SAVE_FILE_DRILL:
710  windowTitle = g_strdup_printf(
711  _("Export \"%s\" layer #%d to "
712  "Excellon drill file as..."),
713  act_file->name, file_index+1);
714 
715  if (GERBV_LAYERTYPE_DRILL != act_file->image->layertype)
716  file_name = g_strconcat (act_file->name, ".drl", NULL);
717  else
718  file_name = g_strdup (act_file->name);
719 
720  dir_name = g_path_get_dirname (act_file->fullPathname);
721  break;
722  case CALLBACKS_SAVE_FILE_DRILLM:
723  windowTitle = g_strdup (_("Export merged visible layers to "
724  "Excellon drill file as..."));
725  if (2 > visible_file_name(&file_name, &dir_name,
726  GERBV_LAYERTYPE_DRILL, "", ".drl")) {
727  error_visible_layers = TRUE;
728  }
729  break;
730  case CALLBACKS_SAVE_FILE_IDRILL:
731  windowTitle = g_strdup_printf(
732  _("Export \"%s\" layer #%d to ISEL NCP drill file as..."),
733  act_file->name, file_index+1);
734  file_name = g_strconcat (act_file->name, ".ncp", NULL);
735  dir_name = g_path_get_dirname (act_file->fullPathname);
736 
737  break;
738  case CALLBACKS_SAVE_FILE_GEDA_PCB:
739  windowTitle = g_strdup_printf (
740  _("Export \"%s\" layer #%d to gEDA PCB file as..."),
741  act_file->name, file_index + 1);
742  file_name = g_strconcat (act_file->name, ".pcb", NULL);
743  dir_name = g_path_get_dirname (act_file->fullPathname);
744  break;
745  case CALLBACKS_SAVE_LAYER_AS:
746  windowTitle = g_strdup_printf (_("Save \"%s\" layer #%d as..."),
747  act_file->name, file_index+1);
748  file_name = g_strdup (act_file->name);
749  dir_name = g_path_get_dirname (act_file->fullPathname);
750  break;
751  }
752 
753  if (file_name != NULL) {
754  gtk_file_chooser_set_current_name (file_chooser_p, file_name);
755  g_free (file_name);
756  }
757  if (dir_name != NULL) {
758  gtk_file_chooser_set_current_folder (file_chooser_p, dir_name);
759  g_free (dir_name);
760  }
761 
762  gtk_dialog_add_buttons (GTK_DIALOG(screen.win.gerber),
763  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
764  GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
765  NULL);
766 
767  gtk_window_set_title (GTK_WINDOW(screen.win.gerber), windowTitle);
768  g_free (windowTitle);
769 
770  if (error_visible_layers) {
771  switch (processType) {
772  case CALLBACKS_SAVE_FILE_RS274XM:
774  _("Not enough Gerber layers are visible"),
775  _("Two or more Gerber layers must be visible "
776  "for export with merge."),
777  FALSE, NULL, NULL, GTK_STOCK_CANCEL);
778  break;
779  case CALLBACKS_SAVE_FILE_DRILLM:
781  _("Not enough Excellon layers are visible"),
782  _("Two or more Excellon layers must be visible "
783  "for export with merge."),
784  FALSE, NULL, NULL, GTK_STOCK_CANCEL);
785  break;
786  default:
788  _("No layers are visible"), _("One or more "
789  "layers must be visible for export."),
790  FALSE, NULL, NULL, GTK_STOCK_CANCEL);
791  }
792 
793  gtk_widget_destroy (screen.win.gerber);
794  callbacks_update_layer_tree ();
795 
796  return;
797  }
798 
799  gtk_widget_show (screen.win.gerber);
800  if (gtk_dialog_run (GTK_DIALOG(screen.win.gerber)) == GTK_RESPONSE_ACCEPT) {
801  new_file_name = gtk_file_chooser_get_filename (file_chooser_p);
802  dpi = gtk_spin_button_get_value_as_int (spin_but);
803  svg_layers = gtk_toggle_button_get_active (
804  GTK_TOGGLE_BUTTON (svg_layers_check));
805  mainProject->use_cairo_svg = gtk_toggle_button_get_active (
806  GTK_TOGGLE_BUTTON (svg_cairo_check));
807  }
808  gtk_widget_destroy (screen.win.gerber);
809 
810  if (!new_file_name) {
811  callbacks_update_layer_tree ();
812 
813  return;
814  }
815 
816  switch (processType) {
817  case CALLBACKS_SAVE_PROJECT_AS:
818  main_save_as_project_from_filename (mainProject, new_file_name);
819  rename_main_window(new_file_name, NULL);
820  break;
821  case CALLBACKS_SAVE_FILE_PS:
823  mainProject, new_file_name);
824  break;
825  case CALLBACKS_SAVE_FILE_PDF:
827  mainProject, new_file_name);
828  break;
829  case CALLBACKS_SAVE_FILE_SVG:
831  mainProject, new_file_name, svg_layers);
832  break;
833  case CALLBACKS_SAVE_FILE_DXF:
834  if (gerbv_export_dxf_file_from_image(new_file_name,
835  act_file->image, &act_file->transform)) {
836  GERB_MESSAGE (
837  _("\"%s\" layer #%d saved as DXF in \"%s\""),
838  act_file->name, file_index + 1,
839  new_file_name);
840  }
841  break;
842  case CALLBACKS_SAVE_FILE_PNG:
843  if (dpi == 0) {
845  mainProject,
846  screenRenderInfo.displayWidth,
847  screenRenderInfo.displayHeight,
848  new_file_name);
849  } else { /* Non zero DPI */
851  gerbv_render_get_boundingbox (mainProject, &bb);
852  gfloat w = bb.right - bb.left;
853  gfloat h = bb.bottom - bb.top;
854  gerbv_render_info_t renderInfo = {
855  dpi, dpi,
856  bb.left - (w*GERBV_DEFAULT_BORDER_COEFF)/2.0,
857  bb.top - (h*GERBV_DEFAULT_BORDER_COEFF)/2.0,
859  w*dpi*(1 + GERBV_DEFAULT_BORDER_COEFF),
860  h*dpi*(1 + GERBV_DEFAULT_BORDER_COEFF),
861  };
863  &renderInfo, new_file_name);
864  }
865 
866  break;
867  case CALLBACKS_SAVE_LAYER_AS:
868  gerbv_save_layer_from_index (mainProject,
869  file_index, new_file_name);
870 
871  /* Rename the file path in the index, so future saves will
872  * reference the new file path */
873  g_free (act_file->fullPathname);
874  act_file->fullPathname = g_strdup (new_file_name);
875  g_free (act_file->name);
876  act_file->name = g_path_get_basename (new_file_name);
877 
878  break;
879  case CALLBACKS_SAVE_FILE_RS274X:
880  if (gerbv_export_rs274x_file_from_image (new_file_name,
881  act_file->image,
882  &act_file->transform)) {
883  GERB_MESSAGE (
884  _("\"%s\" layer #%d saved as Gerber in \"%s\""),
885  act_file->name, file_index + 1,
886  new_file_name);
887  }
888  break;
889  case CALLBACKS_SAVE_FILE_DRILL:
890  if (gerbv_export_drill_file_from_image (new_file_name,
891  act_file->image,
892  &act_file->transform)) {
893  GERB_MESSAGE (
894  _("\"%s\" layer #%d saved as drill in \"%s\""),
895  act_file->name, file_index + 1,
896  new_file_name);
897  }
898  break;
899  case CALLBACKS_SAVE_FILE_IDRILL:
900  if (gerbv_export_isel_drill_file_from_image (new_file_name,
901  act_file->image, &act_file->transform)) {
902  GERB_MESSAGE (
903  _("\"%s\" layer #%d saved as ISEL NCP drill "
904  "in \"%s\""), act_file->name, file_index + 1,
905  new_file_name);
906  }
907  break;
908  case CALLBACKS_SAVE_FILE_GEDA_PCB:
909  if (gerbv_export_geda_pcb_file_from_image(new_file_name,
910  act_file->image, &act_file->transform)) {
911  GERB_MESSAGE (
912  _("\"%s\" layer #%d saved as gEDA PCB "
913  "in \"%s\""), act_file->name, file_index + 1,
914  new_file_name);
915  }
916  break;
917  case CALLBACKS_SAVE_FILE_RS274XM: {
918  gerbv_image_t *image;
919  gerbv_user_transformation_t t = {0,0,1,1,0,FALSE,FALSE,FALSE};
920  if (NULL != (image = merge_images (processType))) {
922  new_file_name, image, &t)) {
923  GERB_MESSAGE (_("Merged visible Gerber layers "
924  "and saved in \"%s\""),
925  new_file_name);
926  }
927  gerbv_destroy_image (image);
928  }
929  break;
930  }
931  case CALLBACKS_SAVE_FILE_DRILLM: {
932  gerbv_image_t *image;
933  gerbv_user_transformation_t t = {0,0,1,1,0,FALSE,FALSE,FALSE};
934  if (NULL != (image = merge_images (processType))) {
936  new_file_name, image, &t);
937  gerbv_destroy_image (image);
938  GERB_MESSAGE (_("Merged visible drill layers "
939  "and saved in \"%s\""),
940  new_file_name);
941  }
942  break;
943  }
944  }
945 
946  g_free (new_file_name);
947  callbacks_update_layer_tree ();
948 
949  return;
950 }
951 
952 /* --------------------------------------------------------- */
953 #if GTK_CHECK_VERSION(2,10,0)
954 
955 static void
956 callbacks_begin_print (GtkPrintOperation *operation, GtkPrintContext *context,
957  gpointer user_data) {
958  gtk_print_operation_set_n_pages (operation, 1);
959 }
960 
961 
962 /* --------------------------------------------------------- */
963 static void
964 callbacks_print_render_page (GtkPrintOperation *operation,
965  GtkPrintContext *context,
966  gint page_nr,
967  gpointer user_data)
968 {
969  GtkPrintSettings *pSettings = gtk_print_operation_get_print_settings (operation);
970  gerbv_render_info_t renderInfo = {1.0, 1.0, 0, 0,
972  (gint) gtk_print_context_get_width (context),
973  (gint) gtk_print_context_get_height (context)};
974  cairo_t *cr;
975 
976  /* have to assume x and y resolutions are the same for now, since we
977  don't support differing scales in the gerb_render_info_t struct yet */
978  gdouble xres = gtk_print_context_get_dpi_x (context);
979  gdouble yres = gtk_print_context_get_dpi_y (context);
980  gdouble scalePercentage = gtk_print_settings_get_scale (pSettings);
981  renderInfo.scaleFactorX = scalePercentage / 100 * xres;
982  renderInfo.scaleFactorY = scalePercentage / 100 * yres;
983 
984  gerbv_render_translate_to_fit_display (mainProject, &renderInfo);
985  cr = gtk_print_context_get_cairo_context (context);
986  gerbv_render_all_layers_to_cairo_target_for_vector_output (mainProject, cr, &renderInfo);
987 }
988 
989 /* --------------------------------------------------------- */
990 void
991 callbacks_print_activate (GtkMenuItem *menuitem, gpointer user_data)
992 {
993  GtkPrintOperation *print;
994  /*GtkPrintOperationResult res;*/
995 
996  print = gtk_print_operation_new ();
997 
998  g_signal_connect (print, "begin_print", G_CALLBACK (callbacks_begin_print), NULL);
999  g_signal_connect (print, "draw_page", G_CALLBACK (callbacks_print_render_page), NULL);
1000 
1001  //GtkPrintSettings *pSettings = gtk_print_operation_get_print_settings (print);
1002 
1003  (void) gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
1004  (GtkWindow *) screen.win.topLevelWindow , NULL);
1005 
1006  g_object_unref (print);
1007 }
1008 #endif /* GTK_CHECK_VERSION(2,10,0) */
1009 
1010 /* --------------------------------------------------------- */
1011 void
1012 callbacks_fullscreen_toggled (GtkMenuItem *menuitem, gpointer user_data)
1013 {
1014  //struct GtkWindow *win = (struct GtkWindow *)(screen.win.topLevelWindow);
1015  GdkWindowState state = gdk_window_get_state (gtk_widget_get_window(screen.win.topLevelWindow));
1016  if(state & GDK_WINDOW_STATE_FULLSCREEN)
1017  gtk_window_unfullscreen (GTK_WINDOW(screen.win.topLevelWindow));
1018  else
1019  gtk_window_fullscreen (GTK_WINDOW(screen.win.topLevelWindow));
1020 }
1021 
1022 /* --------------------------------------------------------- */
1023 void
1024 callbacks_show_toolbar_toggled (GtkMenuItem *menuitem, gpointer user_data)
1025 {
1026  gtk_widget_set_visible (user_data, GTK_CHECK_MENU_ITEM(menuitem)->active);
1027 }
1028 
1029 /* --------------------------------------------------------- */
1030 void
1031 callbacks_show_sidepane_toggled (GtkMenuItem *menuitem, gpointer user_data)
1032 {
1033  gtk_widget_set_visible (user_data, GTK_CHECK_MENU_ITEM(menuitem)->active);
1034 }
1035 
1036 /* --------------------------------------------------------- */
1037 void
1038 callbacks_show_selection_on_invisible (GtkMenuItem *menuitem, gpointer user_data)
1039 {
1040  mainProject->show_invisible_selection = GTK_CHECK_MENU_ITEM(menuitem)->active;
1041  render_refresh_rendered_image_on_screen();
1042 }
1043 
1044 /* --------------------------------------------------------- */
1045 void
1046 callbacks_show_cross_on_drill_holes (GtkMenuItem *menuitem, gpointer user_data)
1047 {
1048  screenRenderInfo.show_cross_on_drill_holes = GTK_CHECK_MENU_ITEM(menuitem)->active;
1049  render_refresh_rendered_image_on_screen();
1050 }
1051 
1052 /* --------------------------------------------------------- */
1056 void
1057 callbacks_toggle_layer_visibility_activate (GtkMenuItem *menuitem, gpointer user_data)
1058 {
1059  int i = GPOINTER_TO_INT(user_data);
1060 
1061  switch (i) {
1062  case LAYER_SELECTED:
1064  [[fallthrough]];
1065  default:
1066  if (0 <= i && i <= mainProject->last_loaded) {
1068  } else {
1069  /* Not in range */
1070  return;
1071  }
1072  break;
1073  case LAYER_ALL_ON:
1074  for (i = 0; i <= mainProject->last_loaded; i++) {
1075  mainProject->file[i]->isVisible = TRUE;
1076  }
1077  break;
1078  case LAYER_ALL_OFF:
1079  for (i = 0; i <= mainProject->last_loaded; i++) {
1080  mainProject->file[i]->isVisible = FALSE;
1081  }
1082  break;
1083  }
1084 
1085  callbacks_update_layer_tree ();
1086 
1087  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
1088  render_refresh_rendered_image_on_screen ();
1089  } else {
1090  render_recreate_composite_surface ();
1091  callbacks_force_expose_event_for_screen ();
1092  }
1093 }
1094 
1095 /* --------------------------------------------------------- */
1096 void
1097 callbacks_zoom_in_activate (GtkMenuItem *menuitem,
1098  gpointer user_data)
1099 {
1100  render_zoom_display (ZOOM_IN, 0, 0, 0);
1101 }
1102 
1103 /* --------------------------------------------------------- */
1104 void
1105 callbacks_zoom_out_activate (GtkMenuItem *menuitem,
1106  gpointer user_data)
1107 {
1108  render_zoom_display (ZOOM_OUT, 0, 0, 0);
1109 }
1110 
1111 /* --------------------------------------------------------- */
1112 void
1113 callbacks_fit_to_window_activate (GtkMenuItem *menuitem,
1114  gpointer user_data)
1115 {
1116  gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
1117  render_refresh_rendered_image_on_screen();
1118 }
1119 
1120 /* --------------------------------------------------------- */
1121 
1122 static const char *error_type_string(gerbv_message_type_t type) {
1123  switch (type) {
1124  case GERBV_MESSAGE_FATAL:
1125  return _("FATAL");
1126  case GERBV_MESSAGE_ERROR:
1127  return _("ERROR");
1128  case GERBV_MESSAGE_WARNING:
1129  return _("Warning");
1130  case GERBV_MESSAGE_NOTE:
1131  return _("Note");
1132  default:
1133  return "Unknown";
1134  }
1135 }
1136 
1137 /* --------------------------------------------------------- */
1144 void
1146  gpointer user_data)
1147 {
1148  gerbv_aperture_list_t *aperture_list;
1149  gchar *str;
1150  int i;
1151 
1152  /* Get a report of stats & errors accumulated from all layers */
1154 
1155  /* General info report */
1156  GString *general_report_str = g_string_new(NULL);
1157  if (stat->layer_count == 0) {
1158  g_string_printf(general_report_str,
1159  _("No Gerber layers visible!"));
1160  } else {
1161  if (stat->error_list->error_text == NULL) {
1162  g_string_printf(general_report_str,
1163  ngettext("No errors found in %d visible "
1164  "Gerber layer.",
1165  "No errors found in %d visible "
1166  "Gerber layers.",
1167  stat->layer_count),
1168  stat->layer_count);
1169  } else {
1170  g_string_printf(general_report_str,
1171  ngettext("Found errors in %d visible "
1172  "Gerber layer.",
1173  "Found errors in %d visible "
1174  "Gerber layers.",
1175  stat->layer_count),
1176  stat->layer_count);
1177  }
1178  }
1179 
1180  GtkWidget *general_label = gtk_label_new(general_report_str->str);
1181  g_string_free(general_report_str, TRUE);
1182  gtk_misc_set_alignment(GTK_MISC(general_label), 0, 0);
1183  gtk_misc_set_padding(GTK_MISC(general_label), 7, 7);
1184  gtk_label_set_selectable(GTK_LABEL(general_label), TRUE);
1185 
1186  struct table *general_table;
1187 
1188  general_table = table_new_with_columns(3,
1189  _("Layer"), G_TYPE_UINT, _("Type"), G_TYPE_STRING,
1190  _("Description"), G_TYPE_STRING);
1191  table_set_column_align(general_table, 0, 1.0);
1192 
1193  for (i = 0; i <= mainProject->last_loaded; i++) {
1194  gerbv_fileinfo_t **files = mainProject->file;
1195 
1196  if (!files[i]
1197  || !files[i]->isVisible
1198  || files[i]->image->layertype != GERBV_LAYERTYPE_RS274X)
1199  continue;
1200 
1201  table_add_row(general_table, i + 1,
1202  _("RS-274X file"), files[i]->fullPathname);
1203 
1204  str = g_strdup_printf(_("%g x %g %s"),
1205  screen_units(fabs(files[i]->image->info->max_x -
1206  files[i]->image->info->min_x)),
1207  screen_units(fabs(files[i]->image->info->max_y -
1208  files[i]->image->info->min_y)),
1209  screen_units_str());
1210  table_add_row(general_table, i + 1, _("Bounding size"), str);
1211  g_free(str);
1212 
1213  /* Check error report on layer */
1214  if (stat->layer_count > 0
1215  && stat->error_list->error_text != NULL) {
1216  for (gerbv_error_list_t *err_list = stat->error_list;
1217  err_list != NULL;
1218  err_list = err_list->next) {
1219 
1220  if (i != err_list->layer - 1)
1221  continue;
1222 
1223  table_add_row(general_table, err_list->layer,
1224  error_type_string(err_list->type),
1225  err_list->error_text);
1226  }
1227  }
1228  }
1229 
1230  /* G codes on active layers */
1231  GtkWidget *G_report_window = gtk_scrolled_window_new(NULL, NULL);
1232  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(G_report_window),
1233  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1234 
1235  struct table *G_table =
1236  table_new_with_columns(3, _("Code"), G_TYPE_STRING,
1237  pgettext("table", "Count"), G_TYPE_UINT,
1238  _("Note"), G_TYPE_STRING);
1239  table_set_column_align(G_table, 0, 1.0);
1240  table_set_column_align(G_table, 1, 1.0);
1241  gtk_tree_view_set_headers_clickable(
1242  GTK_TREE_VIEW(G_table->widget), TRUE);
1243 
1244  table_add_row(G_table, "G00", stat->G0, _(gerber_g_code_name(0)));
1245  table_add_row(G_table, "G01", stat->G1, _(gerber_g_code_name(1)));
1246  table_add_row(G_table, "G02", stat->G2, _(gerber_g_code_name(2)));
1247  table_add_row(G_table, "G03", stat->G3, _(gerber_g_code_name(3)));
1248  table_add_row(G_table, "G04", stat->G4, _(gerber_g_code_name(4)));
1249  table_add_row(G_table, "G10", stat->G10, _(gerber_g_code_name(10)));
1250  table_add_row(G_table, "G11", stat->G11, _(gerber_g_code_name(11)));
1251  table_add_row(G_table, "G12", stat->G12, _(gerber_g_code_name(12)));
1252  table_add_row(G_table, "G36", stat->G36, _(gerber_g_code_name(36)));
1253  table_add_row(G_table, "G37", stat->G37, _(gerber_g_code_name(37)));
1254  table_add_row(G_table, "G54", stat->G54, _(gerber_g_code_name(54)));
1255  table_add_row(G_table, "G55", stat->G55, _(gerber_g_code_name(55)));
1256  table_add_row(G_table, "G70", stat->G70, _(gerber_g_code_name(70)));
1257  table_add_row(G_table, "G71", stat->G71, _(gerber_g_code_name(71)));
1258  table_add_row(G_table, "G74", stat->G74, _(gerber_g_code_name(74)));
1259  table_add_row(G_table, "G75", stat->G75, _(gerber_g_code_name(75)));
1260  table_add_row(G_table, "G90", stat->G90, _(gerber_g_code_name(90)));
1261  table_add_row(G_table, "G91", stat->G91, _(gerber_g_code_name(91)));
1262  table_add_row(G_table, "", stat->G_unknown, _("unknown G-codes"));
1263 
1264  table_set_sortable(G_table);
1265  gtk_container_add(GTK_CONTAINER(G_report_window), G_table->widget);
1266 
1267  /* D codes on active layers */
1268  GtkWidget *D_report_window = gtk_scrolled_window_new(NULL, NULL);
1269  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(D_report_window),
1270  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1271 
1272  struct table *D_table =
1273  table_new_with_columns(3, _("Code"), G_TYPE_STRING,
1274  pgettext("table", "Count"), G_TYPE_UINT,
1275  _("Note"), G_TYPE_STRING);
1276  table_set_column_align(D_table, 0, 1.0);
1277  table_set_column_align(D_table, 1, 1.0);
1278  gtk_tree_view_set_headers_clickable(
1279  GTK_TREE_VIEW(D_table->widget), TRUE);
1280  table_add_row(D_table, "D01", stat->D1, _(gerber_d_code_name(1)));
1281  table_add_row(D_table, "D02", stat->D2, _(gerber_d_code_name(2)));
1282  table_add_row(D_table, "D03", stat->D3, _(gerber_d_code_name(3)));
1283  table_add_row(D_table, "", stat->D_unknown, _("unknown D-codes"));
1284  table_add_row(D_table, "", stat->D_error, _("D-code errors"));
1285 
1286  table_set_sortable(D_table);
1287  gtk_container_add(GTK_CONTAINER(D_report_window), D_table->widget);
1288 
1289  /* M codes on active layers */
1290  GtkWidget *M_report_window = gtk_scrolled_window_new(NULL, NULL);
1291  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(M_report_window),
1292  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1293 
1294  struct table *M_table =
1295  table_new_with_columns(3, _("Code"), G_TYPE_STRING,
1296  pgettext("table", "Count"), G_TYPE_UINT,
1297  _("Note"), G_TYPE_STRING);
1298  table_set_column_align(M_table, 0, 1.0);
1299  table_set_column_align(M_table, 1, 1.0);
1300  gtk_tree_view_set_headers_clickable(
1301  GTK_TREE_VIEW(M_table->widget), TRUE);
1302  table_add_row(M_table, "M00", stat->M0, _(gerber_m_code_name(0)));
1303  table_add_row(M_table, "M01", stat->M1, _(gerber_m_code_name(1)));
1304  table_add_row(M_table, "M02", stat->M2, _(gerber_m_code_name(2)));
1305  table_add_row(M_table, "", stat->M_unknown, _("unknown M-codes"));
1306 
1307  table_set_sortable(M_table);
1308  gtk_container_add(GTK_CONTAINER(M_report_window), M_table->widget);
1309 
1310  /* Misc codes */
1311  GtkWidget *misc_report_window = gtk_scrolled_window_new(NULL, NULL);
1312  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(misc_report_window),
1313  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1314 
1315  struct table *misc_table =
1316  table_new_with_columns(2, _("Code"), G_TYPE_STRING,
1317  pgettext("table", "Count"), G_TYPE_UINT);
1318  table_set_column_align(misc_table, 1, 1.0);
1319  gtk_tree_view_set_headers_clickable(
1320  GTK_TREE_VIEW(misc_table->widget), TRUE);
1321  table_add_row(misc_table, "X", stat->X);
1322  table_add_row(misc_table, "Y", stat->Y);
1323  table_add_row(misc_table, "I", stat->I);
1324  table_add_row(misc_table, "J", stat->J);
1325  table_add_row(misc_table, "*", stat->star);
1326  table_add_row(misc_table, _("Unknown"), stat->unknown);
1327 
1328  table_set_sortable(misc_table);
1329  gtk_container_add(GTK_CONTAINER(misc_report_window),
1330  misc_table->widget);
1331 
1332  /* Apertures definition in input files */
1333  GtkWidget *aperture_def_report_window =
1334  gtk_scrolled_window_new(NULL, NULL);
1335  gtk_scrolled_window_set_policy(
1336  GTK_SCROLLED_WINDOW(aperture_def_report_window),
1337  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1338 
1339  if (stat->aperture_list->number == -1) {
1340  GtkWidget *aperture_def_label = gtk_label_new(
1341  _("No aperture definitions found in active Gerber file(s)!"));
1342  gtk_misc_set_alignment(GTK_MISC(aperture_def_label), 0, 0);
1343  gtk_misc_set_padding(GTK_MISC(aperture_def_label), 7, 7);
1344  gtk_label_set_selectable(GTK_LABEL(aperture_def_label), TRUE);
1345  gtk_scrolled_window_add_with_viewport(
1346  GTK_SCROLLED_WINDOW(aperture_def_report_window),
1347  aperture_def_label);
1348  } else {
1349  struct table *aperture_def_table = table_new_with_columns(6,
1350  _("Layer"), G_TYPE_UINT,
1351  _("D code"), G_TYPE_STRING,
1352  _("Aperture"), G_TYPE_STRING,
1353  _("Param[0]"), G_TYPE_DOUBLE,
1354  _("Param[1]"), G_TYPE_DOUBLE,
1355  _("Param[2]"), G_TYPE_DOUBLE);
1356  table_set_column_align(aperture_def_table, 0, 1.0);
1357  table_set_column_align(aperture_def_table, 1, 1.0);
1358  gtk_tree_view_set_headers_clickable(
1359  GTK_TREE_VIEW(aperture_def_table->widget), TRUE);
1360  gtk_tree_view_set_search_column(
1361  GTK_TREE_VIEW(aperture_def_table->widget), 1);
1362 
1363  GString *gstr = g_string_new(NULL);
1364  for (aperture_list = stat->aperture_list;
1365  aperture_list != NULL;
1366  aperture_list = aperture_list->next) {
1367  g_string_printf(gstr, "D%d", aperture_list->number);
1368  table_add_row(aperture_def_table,
1369  aperture_list->layer,
1370  gstr->str,
1372  aperture_list->type)),
1373  aperture_list->parameter[0],
1374  aperture_list->parameter[1],
1375  aperture_list->parameter[2]);
1376  }
1377  g_string_free(gstr, TRUE);
1378  table_set_sortable(aperture_def_table);
1379  gtk_container_add(GTK_CONTAINER(aperture_def_report_window),
1380  aperture_def_table->widget);
1381  }
1382 
1383  /* Gerber aperture usage on active layers */
1384  GtkWidget *aperture_usage_report_window =
1385  gtk_scrolled_window_new(NULL, NULL);
1386  gtk_scrolled_window_set_policy(
1387  GTK_SCROLLED_WINDOW(aperture_usage_report_window),
1388  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1389 
1390  unsigned int aperture_count = 0;
1391 
1392  if (stat->D_code_list->number == -1) {
1393  GtkWidget *aperture_usage_label = gtk_label_new(
1394  _("No apertures used in Gerber file(s)!"));
1395  gtk_misc_set_alignment(GTK_MISC(aperture_usage_label), 0, 0);
1396  gtk_misc_set_padding(GTK_MISC(aperture_usage_label), 7, 7);
1397  gtk_label_set_selectable(GTK_LABEL(aperture_usage_label), TRUE);
1398  gtk_scrolled_window_add_with_viewport(
1399  GTK_SCROLLED_WINDOW(aperture_usage_report_window),
1400  aperture_usage_label);
1401  } else {
1402  struct table *aperture_usage_table = table_new_with_columns(2,
1403  _("Code"), G_TYPE_STRING,
1404  pgettext("table", "Count"), G_TYPE_UINT);
1405  table_set_column_align(aperture_usage_table, 0, 1.0);
1406  table_set_column_align(aperture_usage_table, 1, 1.0);
1407  gtk_tree_view_set_headers_clickable(
1408  GTK_TREE_VIEW(aperture_usage_table->widget), TRUE);
1409 
1410  GString *gstr = g_string_new(NULL);
1411  for (aperture_list = stat->D_code_list;
1412  aperture_list != NULL;
1413  aperture_list = aperture_list->next) {
1414  g_string_printf(gstr, "D%d", aperture_list->number);
1415  table_add_row(aperture_usage_table,
1416  gstr->str,
1417  aperture_list->count);
1418  aperture_count += aperture_list->count;
1419  }
1420  g_string_free(gstr, TRUE);
1421  table_add_row(aperture_usage_table, _("Total"), aperture_count);
1422  table_set_sortable(aperture_usage_table);
1423  gtk_container_add( GTK_CONTAINER(aperture_usage_report_window),
1424  aperture_usage_table->widget);
1425  }
1426 
1427  /* Create top level dialog window for report */
1428  GtkWidget *analyze_active_gerbers;
1429  analyze_active_gerbers = gtk_dialog_new_with_buttons(
1430  _("Gerber codes report on visible layers"),
1431  NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
1432  GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
1433  gtk_container_set_border_width(GTK_CONTAINER (analyze_active_gerbers), 5);
1434 
1435  gtk_dialog_set_default_response (GTK_DIALOG(analyze_active_gerbers),
1436  GTK_RESPONSE_ACCEPT);
1437  g_signal_connect_after (G_OBJECT(analyze_active_gerbers),
1438  "response",
1439  G_CALLBACK (gtk_widget_destroy),
1440  GTK_WIDGET(analyze_active_gerbers));
1441 
1442  /* Put general report text into scrolled window */
1443  GtkWidget *general_report_window =
1444  gtk_scrolled_window_new(NULL, NULL);
1445  gtk_scrolled_window_set_policy(
1446  GTK_SCROLLED_WINDOW(general_report_window),
1447  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1448 
1449  GtkWidget *vbox = gtk_vbox_new(0, 0);
1450  gtk_box_pack_start(GTK_BOX(vbox), general_label, 0, 0, 0);
1451  gtk_box_pack_start(GTK_BOX(vbox), general_table->widget, 0, 0, 0);
1452  gtk_scrolled_window_add_with_viewport(
1453  GTK_SCROLLED_WINDOW(general_report_window), vbox);
1454 
1455  /* Create tabbed notebook widget and add report widgets. */
1456  GtkWidget *notebook = gtk_notebook_new();
1457 
1458  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1459  GTK_WIDGET(general_report_window),
1460  gtk_label_new(_("General")));
1461 
1462  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1463  GTK_WIDGET(G_report_window),
1464  gtk_label_new(_("G codes")));
1465 
1466  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1467  GTK_WIDGET(D_report_window),
1468  gtk_label_new(_("D codes")));
1469 
1470  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1471  GTK_WIDGET(M_report_window),
1472  gtk_label_new(_("M codes")));
1473 
1474  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1475  GTK_WIDGET(misc_report_window),
1476  gtk_label_new(_("Misc. codes")));
1477 
1478  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1479  GTK_WIDGET(aperture_def_report_window),
1480  gtk_label_new(_("Aperture definitions")));
1481 
1482  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1483  GTK_WIDGET(aperture_usage_report_window),
1484  gtk_label_new(_("Aperture usage")));
1485 
1486  /* Now put notebook into dialog window and show the whole thing */
1487  gtk_container_add(
1488  GTK_CONTAINER(GTK_DIALOG(analyze_active_gerbers)->vbox),
1489  GTK_WIDGET(notebook));
1490 
1491  if (screen.settings) {
1492  analyze_window_size_restore(analyze_active_gerbers);
1493  g_signal_connect (G_OBJECT(analyze_active_gerbers), "response",
1494  G_CALLBACK (analyze_window_size_store),
1495  GTK_WIDGET(analyze_active_gerbers));
1496  } else {
1497  gtk_window_set_default_size(GTK_WINDOW(analyze_active_gerbers),
1498  640, 320);
1499  }
1500 
1501  gtk_widget_show_all(analyze_active_gerbers);
1502 
1503  gerbv_stats_destroy(stat);
1504 }
1505 
1506 /* --------------------------------------------------------- */
1513 void
1515  gpointer user_data)
1516 {
1517  gchar *str;
1518  int i;
1519 
1521 
1522  /* General info report */
1523  GString *general_report_str = g_string_new(NULL);
1524  if (stat->layer_count == 0) {
1525  g_string_printf(general_report_str,
1526  _("No drill layers visible!"));
1527  } else {
1528  if (stat->error_list->error_text == NULL) {
1529  g_string_printf(general_report_str,
1530  ngettext("No errors found in %d visible "
1531  "drill layer.",
1532  "No errors found in %d visible "
1533  "drill layers.",
1534  stat->layer_count),
1535  stat->layer_count);
1536  } else {
1537  g_string_printf(general_report_str,
1538  ngettext("Found errors found in %d visible "
1539  "drill layer.",
1540  "Found errors found in %d visible "
1541  "drill layers.",
1542  stat->layer_count),
1543  stat->layer_count);
1544  }
1545  }
1546 
1547  GtkWidget *general_label = gtk_label_new(general_report_str->str);
1548  g_string_free(general_report_str, TRUE);
1549  gtk_misc_set_alignment(GTK_MISC(general_label), 0, 0);
1550  gtk_misc_set_padding(GTK_MISC(general_label), 7, 7);
1551  gtk_label_set_selectable(GTK_LABEL(general_label), TRUE);
1552 
1553  struct table *general_table;
1554 
1555  general_table = table_new_with_columns(3,
1556  _("Layer"), G_TYPE_UINT, _("Type"), G_TYPE_STRING,
1557  _("Description"), G_TYPE_STRING);
1558  table_set_column_align(general_table, 0, 1.0);
1559 
1560  for (i = 0; i <= mainProject->last_loaded; i++) {
1561  gerbv_fileinfo_t **files = mainProject->file;
1562 
1563  if (!files[i]
1564  || !files[i]->isVisible
1565  || files[i]->image->layertype != GERBV_LAYERTYPE_DRILL)
1566  continue;
1567 
1568  table_add_row(general_table, i + 1,
1569  _("Excellon file"), files[i]->fullPathname);
1570 
1571  str = g_strdup_printf(_("%g x %g %s"),
1572  screen_units(fabs(files[i]->image->info->max_x -
1573  files[i]->image->info->min_x)),
1574  screen_units(fabs(files[i]->image->info->max_y -
1575  files[i]->image->info->min_y)),
1576  screen_units_str());
1577  table_add_row(general_table, i + 1, _("Bounding size"), str);
1578  g_free(str);
1579 
1580  /* Check error report on layer */
1581  if (stat->layer_count > 0
1582  && stat->error_list->error_text != NULL) {
1583  for (gerbv_error_list_t *err_list = stat->error_list;
1584  err_list != NULL;
1585  err_list = err_list->next) {
1586 
1587  if (i != err_list->layer - 1)
1588  continue;
1589 
1590  table_add_row(general_table, err_list->layer,
1591  error_type_string(err_list->type),
1592  err_list->error_text);
1593  }
1594  }
1595  }
1596 
1597  /* G codes on active layers */
1598  GtkWidget *G_report_window = gtk_scrolled_window_new(NULL, NULL);
1599  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(G_report_window),
1600  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1601 
1602  struct table *G_table =
1603  table_new_with_columns(3, _("Code"), G_TYPE_STRING,
1604  pgettext("table", "Count"), G_TYPE_UINT,
1605  _("Note"), G_TYPE_STRING);
1606  table_set_column_align(G_table, 0, 1.0);
1607  table_set_column_align(G_table, 1, 1.0);
1608  gtk_tree_view_set_headers_clickable(
1609  GTK_TREE_VIEW(G_table->widget), TRUE);
1610 
1611  table_add_row(G_table, "G00", stat->G00, _(drill_g_code_name(0)));
1612  table_add_row(G_table, "G01", stat->G01, _(drill_g_code_name(1)));
1613  table_add_row(G_table, "G02", stat->G02, _(drill_g_code_name(2)));
1614  table_add_row(G_table, "G03", stat->G03, _(drill_g_code_name(3)));
1615  table_add_row(G_table, "G04", stat->G04, _(drill_g_code_name(4)));
1616  table_add_row(G_table, "G05", stat->G05, _(drill_g_code_name(5)));
1617  table_add_row(G_table, "G32", stat->G32, _(drill_g_code_name(32)));
1618  table_add_row(G_table, "G33", stat->G33, _(drill_g_code_name(33)));
1619  table_add_row(G_table, "G85", stat->G85, _(drill_g_code_name(85)));
1620  table_add_row(G_table, "G87", stat->G87, _(drill_g_code_name(87)));
1621  table_add_row(G_table, "G90", stat->G90, _(drill_g_code_name(90)));
1622  table_add_row(G_table, "G91", stat->G91, _(drill_g_code_name(91)));
1623  table_add_row(G_table, "G93", stat->G93, _(drill_g_code_name(93)));
1624  table_add_row(G_table, "", stat->G_machine_only, _("machine-only G-codes (ignored)"));
1625  table_add_row(G_table, "", stat->G_unknown, _("unknown G-codes"));
1626 
1627  table_set_sortable(G_table);
1628  gtk_container_add(GTK_CONTAINER(G_report_window), G_table->widget);
1629 
1630  /* M codes on active layers */
1631  GtkWidget *M_report_window = gtk_scrolled_window_new(NULL, NULL);
1632  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(M_report_window),
1633  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1634 
1635  struct table *M_table =
1636  table_new_with_columns(3, _("Code"), G_TYPE_STRING,
1637  pgettext("table", "Count"), G_TYPE_UINT,
1638  _("Note"), G_TYPE_STRING);
1639  table_set_column_align(M_table, 0, 1.0);
1640  table_set_column_align(M_table, 1, 1.0);
1641  gtk_tree_view_set_headers_clickable(
1642  GTK_TREE_VIEW(M_table->widget), TRUE);
1643  table_add_row(M_table, "M00", stat->M00, _(drill_m_code_name(0)));
1644  table_add_row(M_table, "M01", stat->M01, _(drill_m_code_name(1)));
1645  table_add_row(M_table, "M02", stat->M02, _(drill_m_code_name(2)));
1646  table_add_row(M_table, "M18", stat->M18, _(drill_m_code_name(18)));
1647  table_add_row(M_table, "M25", stat->M25, _(drill_m_code_name(25)));
1648  table_add_row(M_table, "M30", stat->M30, _(drill_m_code_name(30)));
1649  table_add_row(M_table, "M45", stat->M45, _(drill_m_code_name(45)));
1650  table_add_row(M_table, "M47", stat->M47, _(drill_m_code_name(47)));
1651  table_add_row(M_table, "M48", stat->M48, _(drill_m_code_name(48)));
1652  table_add_row(M_table, "M70", stat->M70, _(drill_m_code_name(70)));
1653  table_add_row(M_table, "M71", stat->M71, _(drill_m_code_name(71)));
1654  table_add_row(M_table, "M72", stat->M72, _(drill_m_code_name(72)));
1655  table_add_row(M_table, "M80", stat->M80, _(drill_m_code_name(80)));
1656  table_add_row(M_table, "M90", stat->M90, _(drill_m_code_name(90)));
1657  table_add_row(M_table, "M95", stat->M95, _(drill_m_code_name(95)));
1658  table_add_row(M_table, "M97", stat->M97, _(drill_m_code_name(97)));
1659  table_add_row(M_table, "M98", stat->M98, _(drill_m_code_name(98)));
1660  table_add_row(M_table, "", stat->M_machine_only, _("machine-only M-codes (ignored)"));
1661  table_add_row(M_table, "", stat->M_unknown, _("unknown M-codes"));
1662 
1663  table_set_sortable(M_table);
1664  gtk_container_add(GTK_CONTAINER(M_report_window), M_table->widget);
1665 
1666  /* Misc codes */
1667  GtkWidget *misc_report_window = gtk_scrolled_window_new(NULL, NULL);
1668  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(misc_report_window),
1669  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1670 
1671  struct table *misc_table =
1672  table_new_with_columns(2,
1673  /* Count is string for value hide. */
1674  pgettext("table", "Count"), G_TYPE_STRING,
1675  _("Code"), G_TYPE_STRING);
1676  table_set_column_align(misc_table, 0, 1.0);
1677  str = g_strdup_printf("%d", stat->comment);
1678  table_add_row(misc_table, str,_("Comments"));
1679  g_free(str);
1680  str = g_strdup_printf("%d", stat->unknown);
1681  table_add_row(misc_table, str, _("Unknown codes"));
1682  g_free(str);
1683  str = g_strdup_printf("%d", stat->R);
1684  table_add_row(misc_table, str, _("Repeat hole (R)"));
1685  g_free(str);
1686  if (stat->detect != NULL ) {
1687  table_add_row(misc_table, "", stat->detect);
1688  }
1689 
1690  table_set_sortable(misc_table);
1691  gtk_container_add(GTK_CONTAINER(misc_report_window),
1692  misc_table->widget);
1693 
1694  /* Drill usage on active layers */
1695  GtkWidget *drill_usage_report_window =
1696  gtk_scrolled_window_new(NULL, NULL);
1697  gtk_scrolled_window_set_policy(
1698  GTK_SCROLLED_WINDOW(drill_usage_report_window),
1699  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1700 
1701  struct table *drill_usage_table = table_new_with_columns(4,
1702  _("Drill no."), G_TYPE_UINT,
1703  _("Dia."), G_TYPE_DOUBLE,
1704  _("Units"), G_TYPE_STRING,
1705  pgettext("table", "Count"), G_TYPE_UINT);
1706 
1707  table_set_column_align(drill_usage_table, 0, 1.0);
1708  table_set_column_align(drill_usage_table, 3, 1.0);
1709  gtk_tree_view_set_headers_clickable(
1710  GTK_TREE_VIEW(drill_usage_table->widget), TRUE);
1711 
1713  for (drill_list = stat->drill_list;
1714  drill_list != NULL; drill_list = drill_list->next) {
1715  if (drill_list->drill_num == -1)
1716  break; /* No drill list */
1717 
1718  table_add_row(drill_usage_table,
1719  drill_list->drill_num,
1720  drill_list->drill_size,
1721  drill_list->drill_unit,
1722  drill_list->drill_count);
1723  }
1724 
1725  table_set_sortable(drill_usage_table);
1726  gtk_container_add(GTK_CONTAINER(drill_usage_report_window),
1727  drill_usage_table->widget);
1728 
1729  /* Create top level dialog window for report */
1730  GtkWidget *analyze_active_drill;
1731  analyze_active_drill = gtk_dialog_new_with_buttons(
1732  _("Drill codes report on visible layers"),
1733  NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
1734  GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
1735  gtk_container_set_border_width (GTK_CONTAINER (analyze_active_drill), 5);
1736 
1737  gtk_dialog_set_default_response (GTK_DIALOG(analyze_active_drill),
1738  GTK_RESPONSE_ACCEPT);
1739  g_signal_connect_after (G_OBJECT(analyze_active_drill),
1740  "response",
1741  G_CALLBACK (gtk_widget_destroy),
1742  GTK_WIDGET(analyze_active_drill));
1743 
1744  /* Put general report text into scrolled window */
1745  GtkWidget *general_report_window =
1746  gtk_scrolled_window_new(NULL, NULL);
1747  gtk_scrolled_window_set_policy(
1748  GTK_SCROLLED_WINDOW(general_report_window),
1749  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1750 
1751  GtkWidget *vbox = gtk_vbox_new(0, 0);
1752  gtk_box_pack_start(GTK_BOX(vbox), general_label, 0, 0, 0);
1753  gtk_box_pack_start(GTK_BOX(vbox), general_table->widget, 0, 0, 0);
1754  gtk_scrolled_window_add_with_viewport(
1755  GTK_SCROLLED_WINDOW(general_report_window), vbox);
1756 
1757  /* Create tabbed notebook widget and add report widgets. */
1758  GtkWidget *notebook = gtk_notebook_new();
1759 
1760  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1761  GTK_WIDGET(general_report_window),
1762  gtk_label_new(_("General")));
1763 
1764  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1765  GTK_WIDGET(G_report_window),
1766  gtk_label_new(_("G codes")));
1767 
1768  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1769  GTK_WIDGET(M_report_window),
1770  gtk_label_new(_("M codes")));
1771 
1772  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1773  GTK_WIDGET(misc_report_window),
1774  gtk_label_new(_("Misc. codes")));
1775 
1776  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1777  GTK_WIDGET(drill_usage_report_window),
1778  gtk_label_new(_("Drill usage")));
1779 
1780  /* Now put notebook into dialog window and show the whole thing */
1781  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(analyze_active_drill)->vbox),
1782  GTK_WIDGET(notebook));
1783 
1784  if (screen.settings) {
1785  analyze_window_size_restore(analyze_active_drill);
1786  g_signal_connect (G_OBJECT(analyze_active_drill), "response",
1787  G_CALLBACK (analyze_window_size_store),
1788  GTK_WIDGET(analyze_active_drill));
1789  } else {
1790  gtk_window_set_default_size(GTK_WINDOW(analyze_active_drill),
1791  640, 320);
1792  }
1793 
1794  gtk_widget_show_all(analyze_active_drill);
1795 
1797 }
1798 
1799 /* --------------------------------------------------------- */
1800 void
1801 callbacks_control_gerber_options_activate (GtkMenuItem *menuitem,
1802  gpointer user_data)
1803 {
1804 
1805 }
1806 
1807 /* --------------------------------------------------------- */
1808 void
1809 callbacks_online_manual_activate (GtkMenuItem *menuitem,
1810  gpointer user_data)
1811 {
1812 
1813 }
1814 
1815 /* --------------------------------------------------------- */
1822 gboolean
1823 callbacks_quit_activate (GtkMenuItem *menuitem,
1824  gpointer user_data)
1825 {
1826  gboolean layers_dirty = FALSE;
1827  gint idx;
1828 
1829  for (idx = 0; idx<=mainProject->last_loaded; idx++) {
1830  if (mainProject->file[idx] == NULL) break;
1831  layers_dirty = layers_dirty || mainProject->file[idx]->layer_dirty;
1832  }
1833 
1834  if (layers_dirty &&
1836  _("Do you want to close all open layers and quit the program?"),
1837  _("Quitting the program will cause any unsaved changes "
1838  "to be lost."),
1839  FALSE, NULL, GTK_STOCK_QUIT, GTK_STOCK_CANCEL)) {
1840  return TRUE; // stop propagation of the delete_event.
1841  // this would destroy the gui but not return from the gtk event loop.
1842  }
1843 
1844  /* Save background color */
1845  if (screen.settings && !screen.background_is_from_project) {
1846  guint clr;
1847  GdkColor *bg = &mainProject->background;
1848 
1849  clr = bg->red/257<<16 | bg->green/257<<8 | bg->blue/257;
1850  g_settings_set_uint (screen.settings, "background-color", clr);
1851  }
1852 
1853  /* Save main window size and postion */
1854  if (screen.settings) {
1855  GtkWindow *win = GTK_WINDOW(screen.win.topLevelWindow);
1856  gint32 xy[2];
1857  GVariant *var;
1858  gboolean is_max;
1859 
1860  is_max = FALSE != (GDK_WINDOW_STATE_MAXIMIZED & gdk_window_get_state (
1861  gtk_widget_get_window (GTK_WIDGET(win))));
1862  g_settings_set_boolean (screen.settings, "window-maximized", is_max);
1863 
1864  if (!is_max) {
1865  gtk_window_get_size (win, (gint *)xy, (gint *)(xy+1));
1866  var = g_variant_new_fixed_array (G_VARIANT_TYPE_INT32, xy, 2,
1867  sizeof (xy[0]));
1868  g_settings_set_value (screen.settings, "window-size", var);
1869 
1870  gtk_window_get_position (win, (gint *)xy, (gint *)(xy+1));
1871  var = g_variant_new_fixed_array (G_VARIANT_TYPE_INT32, xy, 2,
1872  sizeof (xy[0]));
1873  g_settings_set_value (screen.settings, "window-position", var);
1874  }
1875  }
1876 
1877  gerbv_unload_all_layers (mainProject);
1878  gtk_main_quit();
1879 
1880  return FALSE;
1881 }
1882 
1883 /* --------------------------------------------------------- */
1889 void
1890 callbacks_about_activate (GtkMenuItem *menuitem,
1891  gpointer user_data)
1892 {
1893  GtkWidget *aboutdialog1;
1894  /* TRANSLATORS: Replace this string with your names, one name per line. */
1895  gchar *translators = _("translator-credits");
1896 
1897  gchar *string = g_strdup_printf(_(
1898  "Gerbv — a Gerber (RS-274/X) viewer\n"
1899  "\n"
1900  "Version %s\n"
1901  "Compiled on %s at %s\n"
1902  "\n"
1903  "Gerbv was originally developed as part of the gEDA Project "
1904  "but is now separately maintained.\n"
1905  "\n"
1906  "For more information see:\n"
1907  " gerbv homepage: https://gerbv.github.io/\n"
1908  " gerbv repository: https://github.com/gerbv/gerbv"),
1909  VERSION, __DATE__, __TIME__);
1910 
1911 #if GTK_CHECK_VERSION(2,6,0)
1912  gchar *license = g_strdup_printf(_(
1913  "Gerbv — a Gerber (RS-274/X) viewer\n"
1914  "\n"
1915  "Copyright (C) 2000—2007 Stefan Petersen\n"
1916  "\n"
1917  "This program is free software: you can redistribute it and/or modify\n"
1918  "it under the terms of the GNU General Public License as published by\n"
1919  "the Free Software Foundation, either version 2 of the License, or\n"
1920  "(at your option) any later version.\n"
1921  "\n"
1922  "This program is distributed in the hope that it will be useful,\n"
1923  "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1924  "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1925  "GNU General Public License for more details.\n\n"
1926  "You should have received a copy of the GNU General Public License\n"
1927  "along with this program. If not, see <http://www.gnu.org/licenses/>."));
1928 
1929  #include "authors.c"
1930 
1931  int a_size, i;
1932  gchar **a;
1933 
1934  aboutdialog1 = gtk_about_dialog_new ();
1935  gtk_container_set_border_width (GTK_CONTAINER (aboutdialog1), 5);
1936  gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (aboutdialog1), VERSION);
1937  gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (aboutdialog1), _("Gerbv"));
1938 
1939  gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG (aboutdialog1), translators);
1940  gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (aboutdialog1), string);
1941  gtk_about_dialog_set_license(GTK_ABOUT_DIALOG (aboutdialog1), license);
1942 
1943  /* The authors.c file is autogenerated at build time */
1944  a_size = sizeof(authors_string_array)/sizeof(authors_string_array[0]);
1945  a = g_new(gchar *, a_size);
1946  for (i = 0; i < a_size; i++)
1947  a[i] = _(authors_string_array[i]);
1948 
1949  gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG (aboutdialog1), (const gchar **)a);
1950  gtk_about_dialog_set_website(GTK_ABOUT_DIALOG (aboutdialog1), "https://gerbv.github.io/");
1951  g_free(a);
1952 
1953  g_signal_connect (G_OBJECT(aboutdialog1),"response",
1954  G_CALLBACK (gtk_widget_destroy), GTK_WIDGET(aboutdialog1));
1955 
1956  g_free (string);
1957  g_free (license);
1958 #else
1959  aboutdialog1 = gtk_message_dialog_new ( GTK_WINDOW (screen.win.topLevelWindow),
1960  GTK_DIALOG_DESTROY_WITH_PARENT,
1961  GTK_MESSAGE_INFO,
1962  GTK_BUTTONS_CLOSE,
1963  string
1964  );
1965 
1966  gtk_window_set_title ( GTK_WINDOW (aboutdialog1), _("About Gerbv"));
1967 
1968  /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
1969  g_signal_connect_swapped (aboutdialog1, "response",
1970  G_CALLBACK (gtk_widget_destroy),
1971  aboutdialog1);
1972  g_free (string);
1973 #endif
1974 
1975  gtk_widget_show_all(GTK_WIDGET(aboutdialog1));
1976 
1977 }
1978 
1979 /* --------------------------------------------------------- */
1985 void
1986 callbacks_bugs_activate (GtkMenuItem *menuitem,
1987  gpointer user_data)
1988 {
1989  int i;
1990  #include "bugs.c"
1991 
1992  /* Create the top level dialog widget with an OK button */
1993  GtkWidget *bugs_dialog = gtk_dialog_new_with_buttons(_("Known bugs in Gerbv"),
1994  NULL,
1995  GTK_DIALOG_DESTROY_WITH_PARENT,
1996  GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1997  NULL);
1998  gtk_container_set_border_width (GTK_CONTAINER (bugs_dialog), 5);
1999  gtk_dialog_set_default_response (GTK_DIALOG(bugs_dialog),
2000  GTK_RESPONSE_ACCEPT);
2001  g_signal_connect (G_OBJECT(bugs_dialog), "response",
2002  G_CALLBACK (gtk_widget_destroy), GTK_WIDGET(bugs_dialog));
2003 
2004  /* First create single bugs_string from bugs_string_array */
2005  GString *bugs_string = g_string_new(NULL);
2006  for (i=0; bugs_string_array[i] != NULL; i++) {
2007  /* gettext("") will return info string */
2008  g_string_append_printf(bugs_string, "%s\n",
2009  (bugs_string_array[i][0] == '\0') ? "" : _(bugs_string_array[i]));
2010  }
2011 
2012  /* Create GtkLabel to hold text */
2013  GtkWidget *bugs_label = gtk_label_new (bugs_string->str);
2014  g_string_free(bugs_string, TRUE);
2015  gtk_misc_set_alignment(GTK_MISC(bugs_label), 0, 0);
2016  gtk_misc_set_padding(GTK_MISC(bugs_label), 7, 7);
2017 
2018  /* Put text into scrolled window */
2019  GtkWidget *bugs_window = gtk_scrolled_window_new (NULL, NULL);
2020  gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(bugs_window),
2021  GTK_WIDGET(bugs_label));
2022  gtk_widget_set_size_request(bugs_window, 600, 300);
2023  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(bugs_dialog)->vbox),
2024  GTK_WIDGET(bugs_window));
2025 
2026  gtk_widget_show_all(GTK_WIDGET(bugs_dialog));
2027  gtk_dialog_run(GTK_DIALOG(bugs_dialog));
2028 
2029 }
2030 
2031 /* --------------------------------------------------------- */
2032 gdouble callbacks_calculate_actual_distance (gdouble inputDimension) {
2033  return screen_units(inputDimension);
2034 }
2035 
2036 /* --------------------------------------------------------- */
2037 void callbacks_update_ruler_pointers (void) {
2038  double xPosition, yPosition;
2039  xPosition = screenRenderInfo.lowerLeftX + (screen.last_x / screenRenderInfo.scaleFactorX);
2040  yPosition = screenRenderInfo.lowerLeftY + ((screenRenderInfo.displayHeight - screen.last_y) / screenRenderInfo.scaleFactorY);
2041 
2042  if (!((screen.unit == GERBV_MILS) && ((screenRenderInfo.scaleFactorX < 80)||(screenRenderInfo.scaleFactorY < 80)))) {
2043  xPosition = callbacks_calculate_actual_distance (xPosition);
2044  yPosition = callbacks_calculate_actual_distance (yPosition);
2045  }
2046  g_object_set (G_OBJECT (screen.win.hRuler), "position", xPosition, NULL);
2047  g_object_set (G_OBJECT (screen.win.vRuler), "position", yPosition, NULL);
2048 }
2049 
2050 /* --------------------------------------------------------- */
2051 static void
2052 callbacks_render_type_changed () {
2053  static gboolean isChanging = FALSE;
2054  if (isChanging)
2055  return;
2056 
2057  isChanging = TRUE;
2058  gerbv_render_types_t type = screenRenderInfo.renderType;
2059  GtkCheckMenuItem *check_item = screen.win.menu_view_render_group[type];
2060  DPRINTF("%s(): type = %d, check_item = %p\n", __FUNCTION__, type, check_item);
2061  gtk_check_menu_item_set_active (check_item, TRUE);
2062  gtk_combo_box_set_active (screen.win.sidepaneRenderComboBox, type);
2063 
2064  render_refresh_rendered_image_on_screen();
2065  isChanging = FALSE;
2066 }
2067 
2068 /* --------------------------------------------------------- */
2069 static void
2070 callbacks_units_changed (gerbv_gui_unit_t unit)
2071 {
2072  static gboolean isChanging = FALSE;
2073 
2074  if (isChanging)
2075  return;
2076 
2077  isChanging = TRUE;
2078  screen.unit = unit;
2079 
2080  if (unit == GERBV_MILS || unit == GERBV_MMS || unit == GERBV_INS) {
2081  gtk_combo_box_set_active (
2082  GTK_COMBO_BOX (screen.win.statusUnitComboBox),
2083  unit);
2084  gtk_check_menu_item_set_active (
2085  screen.win.menu_view_unit_group[unit], TRUE);
2086  }
2087 
2088  callbacks_update_ruler_scales ();
2089  callbacks_update_statusbar_coordinates (screen.last_x, screen.last_y);
2090 
2091  if (screen.tool == MEASURE)
2092  callbacks_update_statusbar_measured_distance (
2093  screen.measure_last_x,
2094  screen.measure_last_y);
2095 
2096  isChanging = FALSE;
2097 }
2098 
2099 /* --------------------------------------------------------- */
2100 static void
2101 callbacks_update_ruler_scales (void) {
2102  double xStart, xEnd, yStart, yEnd;
2103 
2104  xStart = screenRenderInfo.lowerLeftX;
2105  yStart = screenRenderInfo.lowerLeftY;
2106  xEnd = screenRenderInfo.lowerLeftX + (screenRenderInfo.displayWidth / screenRenderInfo.scaleFactorX);
2107  yEnd = screenRenderInfo.lowerLeftY + (screenRenderInfo.displayHeight / screenRenderInfo.scaleFactorY);
2108  /* mils can get super crowded with large boards, but inches are too
2109  large for most boards. So, we leave mils in for now and just switch
2110  to inches if the scale factor gets too small */
2111  if (!((screen.unit == GERBV_MILS) && ((screenRenderInfo.scaleFactorX < 80)||(screenRenderInfo.scaleFactorY < 80)))) {
2112  xStart = callbacks_calculate_actual_distance (xStart);
2113  xEnd = callbacks_calculate_actual_distance (xEnd);
2114  yStart = callbacks_calculate_actual_distance (yStart);
2115  yEnd = callbacks_calculate_actual_distance (yEnd);
2116  }
2117  /* make sure the widgets actually exist before setting (in case this gets
2118  called before everything is realized */
2119  if (screen.win.hRuler)
2120  gtk_ruler_set_range (GTK_RULER (screen.win.hRuler), xStart, xEnd, 0, xEnd - xStart);
2121  /* reverse y min and max, since the ruler starts at the top */
2122  if (screen.win.vRuler)
2123  gtk_ruler_set_range (GTK_RULER (screen.win.vRuler), yEnd, yStart, 0, yEnd - yStart);
2124 }
2125 
2126 /* --------------------------------------------------------- */
2127 void callbacks_update_scrollbar_limits (void){
2128  gerbv_render_info_t tempRenderInfo = {0, 0, 0, 0,
2130  screenRenderInfo.displayWidth,
2131  screenRenderInfo.displayHeight};
2132 
2133  GtkAdjustment *hAdjust = (GtkAdjustment *)screen.win.hAdjustment;
2134  GtkAdjustment *vAdjust = (GtkAdjustment *)screen.win.vAdjustment;
2135  gerbv_render_zoom_to_fit_display (mainProject, &tempRenderInfo);
2136  hAdjust->lower = tempRenderInfo.lowerLeftX;
2137  hAdjust->page_increment = hAdjust->page_size;
2138  hAdjust->step_increment = hAdjust->page_size / 10.0;
2139  vAdjust->lower = tempRenderInfo.lowerLeftY;
2140  vAdjust->page_increment = vAdjust->page_size;
2141  vAdjust->step_increment = vAdjust->page_size / 10.0;
2142  hAdjust->upper = tempRenderInfo.lowerLeftX + (tempRenderInfo.displayWidth / tempRenderInfo.scaleFactorX);
2143  hAdjust->page_size = screenRenderInfo.displayWidth / screenRenderInfo.scaleFactorX;
2144  vAdjust->upper = tempRenderInfo.lowerLeftY + (tempRenderInfo.displayHeight / tempRenderInfo.scaleFactorY);
2145  vAdjust->page_size = screenRenderInfo.displayHeight / screenRenderInfo.scaleFactorY;
2146  callbacks_update_scrollbar_positions ();
2147 }
2148 
2149 /* --------------------------------------------------------- */
2150 void callbacks_update_scrollbar_positions (void){
2151  gdouble positionX,positionY;
2152 
2153  positionX = screenRenderInfo.lowerLeftX;
2154  if (positionX < ((GtkAdjustment *)screen.win.hAdjustment)->lower)
2155  positionX = ((GtkAdjustment *)screen.win.hAdjustment)->lower;
2156  if (positionX > (((GtkAdjustment *)screen.win.hAdjustment)->upper - ((GtkAdjustment *)screen.win.hAdjustment)->page_size))
2157  positionX = (((GtkAdjustment *)screen.win.hAdjustment)->upper - ((GtkAdjustment *)screen.win.hAdjustment)->page_size);
2158  gtk_adjustment_set_value ((GtkAdjustment *)screen.win.hAdjustment, positionX);
2159 
2160  positionY = ((GtkAdjustment *)screen.win.vAdjustment)->upper - screenRenderInfo.lowerLeftY -
2161  ((GtkAdjustment *)screen.win.vAdjustment)->page_size +
2162  ((GtkAdjustment *)screen.win.vAdjustment)->lower;
2163  if (positionY < ((GtkAdjustment *)screen.win.vAdjustment)->lower)
2164  positionY = ((GtkAdjustment *)screen.win.vAdjustment)->lower;
2165  if (positionY > (((GtkAdjustment *)screen.win.vAdjustment)->upper - ((GtkAdjustment *)screen.win.vAdjustment)->page_size))
2166  positionY = (((GtkAdjustment *)screen.win.vAdjustment)->upper - ((GtkAdjustment *)screen.win.vAdjustment)->page_size);
2167  gtk_adjustment_set_value ((GtkAdjustment *)screen.win.vAdjustment, positionY);
2168 }
2169 
2170 /* --------------------------------------------------------- */
2171 gboolean
2172 callbacks_scrollbar_button_released (GtkWidget *widget, GdkEventButton *event){
2173  screen.off_x = 0;
2174  screen.off_y = 0;
2175  screen.state = NORMAL;
2176  render_refresh_rendered_image_on_screen();
2177  return FALSE;
2178 }
2179 
2180 /* --------------------------------------------------------- */
2181 gboolean
2182 callbacks_scrollbar_button_pressed (GtkWidget *widget, GdkEventButton *event){
2183  //screen.last_x = ((GtkAdjustment *)screen.win.hAdjustment)->value;
2184  screen.state = SCROLLBAR;
2185  return FALSE;
2186 }
2187 
2188 /* --------------------------------------------------------- */
2189 void callbacks_hadjustment_value_changed (GtkAdjustment *adjustment, gpointer user_data){
2190  /* make sure we're actually using the scrollbar to make sure we don't reset
2191  lowerLeftX during a scrollbar redraw during something else */
2192  if (screen.state == SCROLLBAR) {
2193  screenRenderInfo.lowerLeftX = gtk_adjustment_get_value (adjustment);
2194  }
2195 }
2196 
2197 /* --------------------------------------------------------- */
2198 void callbacks_vadjustment_value_changed (GtkAdjustment *adjustment, gpointer user_data){
2199  /* make sure we're actually using the scrollbar to make sure we don't reset
2200  lowerLeftY during a scrollbar redraw during something else */
2201  if (screen.state == SCROLLBAR) {
2202  screenRenderInfo.lowerLeftY = adjustment->upper -
2203  (gtk_adjustment_get_value (adjustment) + adjustment->page_size) + adjustment->lower;
2204  }
2205 }
2206 
2207 /* --------------------------------------------------------- */
2208 static void
2209 callbacks_layer_tree_visibility_toggled (gint index)
2210 {
2211  mainProject->file[index]->isVisible =
2212  !mainProject->file[index]->isVisible;
2213 
2214  callbacks_update_layer_tree ();
2215  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2216  render_refresh_rendered_image_on_screen ();
2217  } else {
2218  render_recreate_composite_surface ();
2219  callbacks_force_expose_event_for_screen ();
2220  }
2221 }
2222 
2223 /* --------------------------------------------------------- */
2224 static gint
2225 callbacks_get_col_num_from_tree_view_col (GtkTreeViewColumn *col)
2226 {
2227  GList *cols;
2228  gint num;
2229 
2230  g_return_val_if_fail ( col != NULL, -1 );
2231  g_return_val_if_fail ( col->tree_view != NULL, -1 );
2232  cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(col->tree_view));
2233  num = g_list_index(cols, (gpointer) col);
2234  g_list_free(cols);
2235  return num;
2236 }
2237 
2238 /* --------------------------------------------------------- */
2239 void
2240 callbacks_add_layer_button_clicked (GtkButton *button, gpointer user_data)
2241 {
2242  callbacks_open_activate (NULL, NULL);
2243 }
2244 
2245 /* --------------------------------------------------------- */
2246 void
2247 callbacks_unselect_all_tool_buttons (void) {
2248 
2249 }
2250 
2251 void
2252 callbacks_switch_to_normal_tool_cursor (gint toolNumber)
2253 {
2254  GdkWindow *drawing_area_window = screen.drawing_area->window;
2255  GdkCursor *cursor;
2256 
2257  switch (toolNumber) {
2258  case POINTER:
2259  gdk_window_set_cursor(drawing_area_window, GERBV_DEF_CURSOR);
2260  break;
2261  case PAN:
2262  cursor = gdk_cursor_new(GDK_FLEUR);
2263  gdk_window_set_cursor(drawing_area_window, cursor);
2264  gdk_cursor_destroy(cursor);
2265  break;
2266  case ZOOM:
2267  cursor = gdk_cursor_new(GDK_SIZING);
2268  gdk_window_set_cursor(drawing_area_window, cursor);
2269  gdk_cursor_destroy(cursor);
2270  break;
2271  case MEASURE:
2272  cursor = gdk_cursor_new(GDK_CROSSHAIR);
2273  gdk_window_set_cursor(drawing_area_window, cursor);
2274  gdk_cursor_destroy(cursor);
2275  break;
2276  default:
2277  break;
2278  }
2279 }
2280 
2281 /* --------------------------------------------------------- */
2282 void
2283 callbacks_switch_to_correct_cursor (void)
2284 {
2285  GdkWindow *drawing_area_window = screen.drawing_area->window;
2286  GdkCursor *cursor;
2287 
2288  if (screen.state == IN_MOVE) {
2289  cursor = gdk_cursor_new(GDK_FLEUR);
2290  gdk_window_set_cursor(drawing_area_window, cursor);
2291  gdk_cursor_destroy(cursor);
2292  return;
2293  }
2294  else if (screen.state == IN_ZOOM_OUTLINE) {
2295  cursor = gdk_cursor_new(GDK_SIZING);
2296  gdk_window_set_cursor(drawing_area_window, cursor);
2297  gdk_cursor_destroy(cursor);
2298  return;
2299  }
2300  callbacks_switch_to_normal_tool_cursor (screen.tool);
2301 }
2302 
2303 /* --------------------------------------------------------- */
2304 void
2305 callbacks_change_tool (GtkButton *button, gpointer user_data) {
2306  gint toolNumber = GPOINTER_TO_INT (user_data);
2307 
2308  /* make sure se don't get caught in endless recursion here */
2309  if (screen.win.updatingTools)
2310  return;
2311  screen.win.updatingTools = TRUE;
2312  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPointer), FALSE);
2313  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPan), FALSE);
2314  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonZoom), FALSE);
2315  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonMeasure), FALSE);
2316  switch (toolNumber) {
2317  case POINTER:
2318  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPointer), TRUE);
2319  screen.tool = POINTER;
2320  screen.state = NORMAL;
2321  utf8_strncpy(screen.statusbar.diststr,
2322  _("Click to select objects in the active layer. "
2323  "Middle click and drag to pan."),
2324  MAX_DISTLEN);
2325  break;
2326  case PAN:
2327  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPan), TRUE);
2328  screen.tool = PAN;
2329  screen.state = NORMAL;
2330  utf8_strncpy(screen.statusbar.diststr,
2331  _("Click and drag to pan. Right click and drag to zoom."),
2332  MAX_DISTLEN);
2333  break;
2334  case ZOOM:
2335  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonZoom), TRUE);
2336  screen.tool = ZOOM;
2337  screen.state = NORMAL;
2338  utf8_strncpy(screen.statusbar.diststr,
2339  _("Click and drag to zoom in. Shift+click to zoom out."),
2340  MAX_DISTLEN);
2341  break;
2342 
2343  case MEASURE:
2344  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonMeasure), TRUE);
2345  screen.tool = MEASURE;
2346  screen.state = NORMAL;
2347  utf8_strncpy(screen.statusbar.diststr,
2348  _("Click and drag to measure a distance or select two apertures."),
2349  MAX_DISTLEN);
2350 
2351  /* To not show previous measure drag-line */
2352  screen.measure_start_x = 0;
2353  screen.measure_start_y = 0;
2354  screen.measure_stop_x = 0;
2355  screen.measure_stop_y = 0;
2356 
2357  /* If two items are selected, measure they distance */
2358  if (selection_length (&screen.selectionInfo) == 2) {
2359  gerbv_selection_item_t item[2];
2360  gerbv_net_t *net[2];
2361 
2362  item[0] = selection_get_item_by_index(
2363  &screen.selectionInfo, 0);
2364  item[1] = selection_get_item_by_index(
2365  &screen.selectionInfo, 1);
2366  net[0] = item[0].net;
2367  net[1] = item[1].net;
2368 
2369  if ((net[0]->aperture_state ==
2370  net[1]->aperture_state)
2371  && (net[0]->aperture_state ==
2373  screen.measure_start_x = net[0]->stop_x;
2374  screen.measure_start_y = net[0]->stop_y;
2376  &screen.measure_start_x,
2377  &screen.measure_start_y,
2378  item[0].image,
2379  mainProject);
2380 
2381  screen.measure_stop_x = net[1]->stop_x;
2382  screen.measure_stop_y = net[1]->stop_y;
2384  &screen.measure_stop_x,
2385  &screen.measure_stop_y,
2386  item[1].image,
2387  mainProject);
2388 
2390  }
2391  }
2392  break;
2393  default:
2394  break;
2395  }
2396 
2397  callbacks_switch_to_normal_tool_cursor (toolNumber);
2399  screen.win.updatingTools = FALSE;
2400  callbacks_force_expose_event_for_screen();
2401 }
2402 
2403 /* --------------------------------------------------------- */
2404 static void
2405 callbacks_select_layer_row (gint rowIndex)
2406 {
2407  GtkTreeSelection *selection;
2408  GtkTreeIter iter;
2409  GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2410  ((GtkTreeView *) screen.win.layerTree);
2411 
2412  selection = gtk_tree_view_get_selection((GtkTreeView *) screen.win.layerTree);
2413 
2414  if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store),
2415  &iter, NULL, rowIndex)) {
2416  gtk_tree_selection_select_iter (selection, &iter);
2417  }
2418 }
2419 
2420 /* --------------------------------------------------------- */
2426 static gint
2428 {
2429  GtkTreeSelection *selection;
2430  GtkTreeIter iter;
2431  GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2432  ((GtkTreeView *) screen.win.layerTree);
2433  gint index=-1,i=0;
2434 
2435  /* This will only work in single or browse selection mode! */
2436  selection = gtk_tree_view_get_selection((GtkTreeView *) screen.win.layerTree);
2437  if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
2438  while (gtk_tree_model_iter_nth_child ((GtkTreeModel *)list_store,
2439  &iter, NULL, i)){
2440  if (gtk_tree_selection_iter_is_selected (selection, &iter)) {
2441  return i;
2442  }
2443  i++;
2444  }
2445  }
2446  return index;
2447 }
2448 
2449 /* --------------------------------------------------------- */
2450 void
2451 callbacks_remove_layer_button_clicked (GtkButton *button, gpointer user_data)
2452 {
2453  gint index = callbacks_get_selected_row_index ();
2454 
2455  if ((index >= 0) && (index <= mainProject->last_loaded)) {
2456  render_remove_selected_objects_belonging_to_layer (
2457  &screen.selectionInfo,
2458  mainProject->file[index]->image);
2459  update_selected_object_message (FALSE);
2460 
2461  gerbv_unload_layer (mainProject, index);
2462  callbacks_update_layer_tree ();
2463 
2464  index = MAX(0, index - 1);
2465  callbacks_select_layer_row (index);
2466 
2467  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2468  render_refresh_rendered_image_on_screen ();
2469  } else {
2470  render_recreate_composite_surface ();
2471  callbacks_force_expose_event_for_screen ();
2472  }
2473  }
2474 }
2475 
2476 /* --------------------------------------------------------- */
2477 void
2478 callbacks_move_layer_down_menu_activate (GtkMenuItem *menuitem, gpointer user_data) {
2479  callbacks_move_layer_down_button_clicked(NULL, NULL);
2480  gtk_widget_grab_focus (screen.win.layerTree);
2481 }
2482 
2483 /* --------------------------------------------------------- */
2484 void
2485 callbacks_move_layer_down_button_clicked (GtkButton *button, gpointer user_data) {
2486  gint index=callbacks_get_selected_row_index();
2487  if (index < 0) {
2488  show_no_layers_warning ();
2489  return;
2490  }
2491 
2492  if (index < mainProject->last_loaded) {
2493  gerbv_change_layer_order (mainProject, index, index + 1);
2494  callbacks_update_layer_tree ();
2495  callbacks_select_layer_row (index + 1);
2496 
2497  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2498  render_refresh_rendered_image_on_screen ();
2499  }
2500  else {
2501  render_recreate_composite_surface ();
2502  callbacks_force_expose_event_for_screen ();
2503  }
2504  }
2505 }
2506 
2507 /* --------------------------------------------------------- */
2508 void
2509 callbacks_move_layer_up_menu_activate (GtkMenuItem *menuitem, gpointer user_data) {
2510  callbacks_move_layer_up_button_clicked (NULL, NULL);
2511  gtk_widget_grab_focus (screen.win.layerTree);
2512 }
2513 
2514 /* --------------------------------------------------------- */
2515 void
2516 callbacks_move_layer_up_button_clicked (GtkButton *button, gpointer user_data) {
2517  gint index=callbacks_get_selected_row_index();
2518  if (index < 0) {
2519  show_no_layers_warning ();
2520  return;
2521  }
2522  if (index > 0) {
2523  gerbv_change_layer_order (mainProject, index, index - 1);
2524  callbacks_update_layer_tree ();
2525  callbacks_select_layer_row (index - 1);
2526  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2527  render_refresh_rendered_image_on_screen();
2528  }
2529  else {
2530  render_recreate_composite_surface ();
2531  callbacks_force_expose_event_for_screen ();
2532  }
2533  }
2534 }
2535 
2536 /* --------------------------------------------------------- */
2537 void callbacks_layer_tree_row_inserted (GtkTreeModel *tree_model, GtkTreePath *path,
2538  GtkTreeIter *oIter, gpointer user_data) {
2539  gint *indices=NULL,oldPosition,newPosition;
2540 
2541  if ((!screen.win.treeIsUpdating)&&(path != NULL)) {
2542  indices = gtk_tree_path_get_indices (path);
2543  if (indices) {
2544  newPosition = indices[0];
2545  oldPosition = callbacks_get_selected_row_index ();
2546  /* compensate for the fact that the old row has already
2547  been removed */
2548  if (oldPosition < newPosition)
2549  newPosition--;
2550  else
2551  oldPosition--;
2552  gerbv_change_layer_order (mainProject, oldPosition, newPosition);
2553 
2554  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2555  render_refresh_rendered_image_on_screen();
2556  }
2557  else {
2558  render_recreate_composite_surface ();
2559  callbacks_force_expose_event_for_screen ();
2560  }
2561  /* select the new line */
2562  GtkTreeSelection *selection;
2563  GtkTreeIter iter;
2564  GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2565  ((GtkTreeView *) screen.win.layerTree);
2566 
2567  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(screen.win.layerTree));
2568  if (gtk_tree_model_get_iter ((GtkTreeModel *)list_store, &iter, path))
2569  gtk_tree_selection_select_iter (selection, &iter);
2570  }
2571  }
2572 }
2573 
2574 /* --------------------------------------------------------- */
2575 void
2576 callbacks_show_color_picker_dialog (gint index){
2577  screen.win.colorSelectionDialog = NULL;
2578  GtkColorSelectionDialog *cs= (GtkColorSelectionDialog *) gtk_color_selection_dialog_new (_("Select a color"));
2579  GtkColorSelection *colorsel = (GtkColorSelection *) cs->colorsel;
2580 
2581  screen.win.colorSelectionDialog = (GtkWidget *) cs;
2582  screen.win.colorSelectionIndex = index;
2583  if (index >= 0)
2584  gtk_color_selection_set_current_color (colorsel, &mainProject->file[index]->color);
2585  else
2586  gtk_color_selection_set_current_color (colorsel, &mainProject->background);
2587  if ((screenRenderInfo.renderType >= GERBV_RENDER_TYPE_CAIRO_NORMAL)&&(index >= 0)) {
2588  gtk_color_selection_set_has_opacity_control (colorsel, TRUE);
2589  gtk_color_selection_set_current_alpha (colorsel, mainProject->file[index]->alpha);
2590  }
2591  gtk_widget_show_all((GtkWidget *)cs);
2592  if (gtk_dialog_run ((GtkDialog*)cs) == GTK_RESPONSE_OK) {
2593  GtkColorSelection *colorsel = (GtkColorSelection *) cs->colorsel;
2594  gint rowIndex = screen.win.colorSelectionIndex;
2595 
2596  if (index >= 0) {
2597  gtk_color_selection_get_current_color (colorsel, &mainProject->file[rowIndex]->color);
2598  gdk_colormap_alloc_color(gdk_colormap_get_system(), &mainProject->file[rowIndex]->color, FALSE, TRUE);
2599  }
2600  else {
2601  gtk_color_selection_get_current_color (colorsel, &mainProject->background);
2602  gdk_colormap_alloc_color(gdk_colormap_get_system(), &mainProject->background, FALSE, TRUE);
2603  }
2604  if ((screenRenderInfo.renderType >= GERBV_RENDER_TYPE_CAIRO_NORMAL)&&(index >= 0)) {
2605  mainProject->file[rowIndex]->alpha = gtk_color_selection_get_current_alpha (colorsel);
2606  }
2607 
2608  callbacks_update_layer_tree ();
2609  render_refresh_rendered_image_on_screen();
2610  }
2611  gtk_widget_destroy ((GtkWidget *)cs);
2612  screen.win.colorSelectionDialog = NULL;
2613 }
2614 
2615 /* --------------------------------------------------------- */
2616 void
2617 callbacks_invert_layer_clicked (GtkButton *button, gpointer user_data) {
2618  gint index=callbacks_get_selected_row_index();
2619  if (index < 0) {
2620  show_no_layers_warning ();
2621  return;
2622  }
2624  render_refresh_rendered_image_on_screen ();
2625  callbacks_update_layer_tree ();
2626 }
2627 
2628 /* --------------------------------------------------------- */
2629 void
2630 callbacks_change_layer_color_clicked (GtkButton *button, gpointer user_data) {
2631  gint index=callbacks_get_selected_row_index();
2632  if (index < 0) {
2633  show_no_layers_warning ();
2634  return;
2635  }
2636  callbacks_show_color_picker_dialog (index);
2637 }
2638 
2639 void
2640 callbacks_change_background_color_clicked (GtkButton *button, gpointer user_data) {
2641  callbacks_show_color_picker_dialog (-1);
2642 }
2643 
2644 /* --------------------------------------------------------------------------- */
2645 void
2646 callbacks_reload_layer_clicked (GtkButton *button, gpointer user_data)
2647 {
2648  gint index = callbacks_get_selected_row_index ();
2649 
2650  if (index < 0) {
2651  show_no_layers_warning ();
2652  return;
2653  }
2654 
2655  render_remove_selected_objects_belonging_to_layer (
2656  &screen.selectionInfo, mainProject->file[index]->image);
2657  update_selected_object_message (FALSE);
2658 
2659  gerbv_revert_file (mainProject, index);
2660  render_refresh_rendered_image_on_screen ();
2661  callbacks_update_layer_tree();
2662 }
2663 
2664 void
2665 callbacks_change_layer_edit_clicked (GtkButton *button, gpointer userData)
2666 {
2667  gint index = callbacks_get_selected_row_index();
2668  gerbv_fileinfo_t **files = mainProject->file;
2669  gerbv_user_transformation_t **transforms;
2670  int i, j;
2671 
2672  if (index < 0) {
2673  show_no_layers_warning ();
2674  return;
2675  }
2676 
2677  /* last_loaded == 0 if only one file is loaded */
2678  transforms = g_new (gerbv_user_transformation_t *,
2680  2 /* layer + NULL */ +
2681  1 /* if selected layer is visible */);
2682 
2683  /* [0] is selected layer */
2684  transforms[0] = &mainProject->file[index]->transform;
2685 
2686  /* Get visible Gerber files transformations */
2687  j = 1; /* [0] is alerady used */
2688  for (i = 0; i <= mainProject->last_loaded; i++) {
2689  if (files[i] && files[i]->isVisible)
2690  transforms[j++] = &files[i]->transform;
2691  }
2692 
2693  /* Terminate array with NULL */
2694  transforms[j] = NULL;
2695 
2696  interface_show_layer_edit_dialog(transforms, screen.unit);
2697  g_free (transforms);
2698  render_refresh_rendered_image_on_screen ();
2699  callbacks_update_layer_tree ();
2700 }
2701 
2702 /* --------------------------------------------------------------------------- */
2703 void
2704 callbacks_change_layer_format_clicked (GtkButton *button, gpointer user_data)
2705 {
2706  gerbv_HID_Attribute *attr = NULL;
2707  int n = 0;
2708  int i;
2709  gerbv_HID_Attr_Val * results = NULL;
2710  gint index = callbacks_get_selected_row_index();
2711  gchar *type;
2712  gint rc;
2713  if (index < 0) {
2714  show_no_layers_warning ();
2715  return;
2716  }
2717  DPRINTF("%s(): index = %d\n", __FUNCTION__, index);
2718  attr = mainProject->file[index]->image->info->attr_list;
2719  n = mainProject->file[index]->image->info->n_attr;
2720  type = mainProject->file[index]->image->info->type;
2721  if (type == NULL)
2722  type = N_("Unknown type");
2723 
2724  if (attr == NULL || n == 0)
2725  {
2726  interface_show_alert_dialog(_("This file type does not currently have any editable features"),
2727  _("Format editing is currently only supported for Excellon drill file formats."),
2728  FALSE,
2729  NULL);
2730  return;
2731  }
2732 
2733  DPRINTF("%s(): n = %d, attr = %p\n", __FUNCTION__, n, attr);
2734  if (n > 0)
2735  {
2736  if (mainProject->file[index]->layer_dirty) {
2738  _("This layer has changed!"),
2739  _("Editing the file type will reload the layer, "
2740  "destroying your changes. Click OK to edit "
2741  "the file type and destroy your changes, "
2742  "or Cancel to leave."),
2743  TRUE, NULL, GTK_STOCK_OK, GTK_STOCK_CANCEL);
2744  if (rc == 0) return; /* Return if user hit Cancel */
2745  }
2746 
2747  results = (gerbv_HID_Attr_Val *) malloc (n * sizeof (gerbv_HID_Attr_Val));
2748  if (results == NULL)
2749  GERB_FATAL_ERROR("%s(): malloc failed", __FUNCTION__);
2750 
2751  /* non-zero means cancel was picked */
2752  if (attribute_interface_dialog (attr, n, results,
2753  _("Edit file format"),
2754  _(type)))
2755  {
2756  return;
2757  }
2758 
2759  }
2760 
2761  DPRINTF("%s(): reloading layer\n", __func__);
2762  gerbv_revert_file (mainProject, index);
2763 
2764  for (i = 0; i < n; i++)
2765  {
2766  if (results[i].str_value)
2767  free (results[i].str_value);
2768  }
2769 
2770  if (results)
2771  free (results);
2772  render_refresh_rendered_image_on_screen();
2773  callbacks_update_layer_tree();
2774 }
2775 
2776 /* --------------------------------------------------------------------------- */
2777 gboolean
2778 callbacks_file_drop_event(GtkWidget *widget, GdkDragContext *dc,
2779  gint x, gint y, GtkSelectionData *data,
2780  guint info, guint time, gpointer p)
2781 {
2782  gchar **uris, **uri;
2783  GSList *fns = NULL;
2784 
2785  uris = gtk_selection_data_get_uris(data);
2786  if (!uris)
2787  return FALSE;
2788 
2789  for (uri = uris; *uri; uri++) {
2790  const char *prefix_str =
2791 #ifdef WIN32
2792  "file:///";
2793 #else
2794  "file://";
2795 #endif
2796  if (g_strrstr(*uri, prefix_str) == *uri)
2797  fns = g_slist_append(fns, g_uri_unescape_string(
2798  *uri + strlen(prefix_str), NULL));
2799  }
2800 
2801  open_files(fns);
2802  g_slist_free_full(fns, g_free);
2803  g_strfreev(uris);
2804 
2805  return TRUE;
2806 }
2807 
2808 /* --------------------------------------------------------------------------- */
2809 gboolean
2810 callbacks_layer_tree_key_press (GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
2811  /* if space is pressed while a color picker icon is in focus,
2812  show the color picker dialog. */
2813 
2814  if(event->keyval == GDK_space){
2815  GtkTreeView *tree;
2816  GtkTreePath *path;
2817  GtkTreeViewColumn *col;
2818  gint *indices;
2819  gint idx;
2820 
2821  tree = (GtkTreeView *) screen.win.layerTree;
2822  gtk_tree_view_get_cursor (tree, &path, &col);
2823  if (path) {
2824  indices = gtk_tree_path_get_indices (path);
2825  if (indices) {
2826  idx = callbacks_get_col_num_from_tree_view_col (col);
2827  if ((idx == 1) && (indices[0] <= mainProject->last_loaded)){
2828  callbacks_show_color_picker_dialog (indices[0]);
2829  }
2830  }
2831  gtk_tree_path_free (path);
2832  }
2833  }
2834  /* by default propagate the key press */
2835  return FALSE;
2836 }
2837 
2838 /* --------------------------------------------------------------------------- */
2839 gboolean
2840 callbacks_layer_tree_button_press (GtkWidget *widget, GdkEventButton *event,
2841  gpointer user_data)
2842 {
2843  GtkTreePath *path;
2844  GtkTreeIter iter;
2845  GtkTreeViewColumn *col;
2846  gint x,y;
2847  gint *indices;
2848 
2849  GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model (
2850  (GtkTreeView *) screen.win.layerTree);
2851 
2852  if (event->button == 1) {
2853  if (gtk_tree_view_get_path_at_pos ((GtkTreeView *) widget,
2854  event->x, event->y, &path, &col, &x, &y)
2855  && gtk_tree_model_get_iter ((GtkTreeModel *)list_store,
2856  &iter, path)) {
2857  indices = gtk_tree_path_get_indices (path);
2858  if (indices && (indices[0] <= mainProject->last_loaded)) {
2859  switch (callbacks_get_col_num_from_tree_view_col (col)) {
2860  case 0:
2861  callbacks_select_layer_row (indices[0]);
2862  callbacks_layer_tree_visibility_toggled (indices[0]);
2863  return TRUE;
2864  case 1:
2865  callbacks_show_color_picker_dialog (indices[0]);
2866  /* don't propagate the signal, since drag and drop can
2867  sometimes activated during color selection */
2868  return TRUE;
2869  }
2870  }
2871  }
2872  }
2873  /* don't pop up the menu if we don't have any loaded files */
2874  else if ((event->button == 3)&&(mainProject->last_loaded >= 0)) {
2875  gtk_menu_popup (GTK_MENU (screen.win.layerTreePopupMenu),
2876  NULL, NULL, NULL, NULL,
2877  event->button, event->time);
2878  }
2879 
2880  /* always allow the click to propagate and make sure the line is activated */
2881  return FALSE;
2882 }
2883 
2884 /* --------------------------------------------------------------------------- */
2885 void
2886 callbacks_update_layer_tree (void)
2887 {
2888  GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2889  ((GtkTreeView *) screen.win.layerTree);
2890  gint idx;
2891  GtkTreeIter iter;
2892  GtkTreeSelection *selection;
2893  gint oldSelectedRow;
2894 
2895  if (screen.win.treeIsUpdating)
2896  return;
2897 
2898  screen.win.treeIsUpdating = TRUE;
2899 
2900  oldSelectedRow = callbacks_get_selected_row_index();
2901  if (oldSelectedRow < 0)
2902  oldSelectedRow = 0;
2903 
2904  gtk_list_store_clear (list_store);
2905 
2906  for (idx = 0; idx <= mainProject->last_loaded; idx++) {
2907  GdkPixbuf *pixbuf, *blackPixbuf;
2908  unsigned char red, green, blue, alpha;
2909  guint32 color;
2910  gchar *layerName;
2911  gerbv_fileinfo_t *file;
2912 
2913  file = mainProject->file[idx];
2914  if (!file)
2915  continue;
2916 
2917  red = (unsigned char) (file->color.red * 255 / G_MAXUINT16);
2918  green = (unsigned char) (file->color.green * 255 / G_MAXUINT16);
2919  blue = (unsigned char) (file->color.blue *255 / G_MAXUINT16);
2920  alpha = (unsigned char) (file->alpha * 255 / G_MAXUINT16);
2921 
2922  color = red*(256*256*256) + green*(256*256) + blue*256 + alpha;
2923  pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 20, 15);
2924  gdk_pixbuf_fill (pixbuf, color);
2925 
2926  blackPixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 20, 15);
2927  color = 100*(256*256*256) + 100*(256*256) + 100*256 + 150;
2928  gdk_pixbuf_fill (blackPixbuf, color);
2929 
2930  /* copy the color area into the black pixbuf */
2931  gdk_pixbuf_copy_area (pixbuf, 1, 1, 18, 13, blackPixbuf, 1, 1);
2932  g_object_unref(pixbuf);
2933 
2934  gtk_list_store_append (list_store, &iter);
2935 
2936  gchar startChar[2],*modifiedCode;
2937  /* terminate the letter string */
2938  startChar[1] = 0;
2939 
2940  gint numberOfModifications = 0;
2941  if (file->transform.inverted) {
2942  startChar[0] = 'I';
2943  numberOfModifications++;
2944  }
2945  if (file->transform.mirrorAroundX
2946  || file->transform.mirrorAroundY) {
2947  startChar[0] = 'M';
2948  numberOfModifications++;
2949  }
2950  if (fabs(file->transform.translateX)
2951  > GERBV_PRECISION_LINEAR_INCH
2952  || fabs(file->transform.translateY)
2953  > GERBV_PRECISION_LINEAR_INCH) {
2954  startChar[0] = 'T';
2955  numberOfModifications++;
2956  }
2957  if (fabs(file->transform.scaleX - 1)
2958  > GERBV_PRECISION_LINEAR_INCH
2959  || fabs(file->transform.scaleY - 1)
2960  > GERBV_PRECISION_LINEAR_INCH) {
2961  startChar[0] = 'S';
2962  numberOfModifications++;
2963  }
2964  if (fabs(file->transform.rotation)
2965  > GERBV_PRECISION_ANGLE_RAD) {
2966  startChar[0] = 'R';
2967  numberOfModifications++;
2968  }
2969  if (numberOfModifications > 1)
2970  startChar[0] = '*';
2971  if (numberOfModifications == 0)
2972  modifiedCode = g_strdup ("");
2973  else
2974  modifiedCode = g_strdup (startChar);
2975 
2976  /* Display any unsaved layers differently to show the user they
2977  * are unsaved */
2978  if (file->layer_dirty == TRUE) {
2979  /* The layer has unsaved changes in it. Show layer name
2980  * in italics. */
2981  layerName = g_strconcat ("*", "<i>", file->name,
2982  "</i>", NULL);
2983  } else {
2984  /* Layer is clean. Show layer name using normal font. */
2985  layerName = g_strdup (file->name);
2986  }
2987 
2988  gtk_list_store_set (list_store, &iter,
2989  0, file->isVisible,
2990  1, blackPixbuf,
2991  2, layerName,
2992  3, modifiedCode,
2993  -1);
2994  g_free (layerName);
2995  g_free (modifiedCode);
2996  /* pixbuf has a refcount of 2 now, as the list store has added its own reference */
2997  g_object_unref(blackPixbuf);
2998  }
2999 
3000  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(screen.win.layerTree));
3001 
3002  /* if no line is selected yet, select the first row (if it has data) */
3003  /* or, select the line that was previously selected */
3004 
3005  if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
3006  if (gtk_tree_model_iter_nth_child ((GtkTreeModel *) list_store,
3007  &iter, NULL, oldSelectedRow)) {
3008  gtk_tree_selection_select_iter (selection, &iter);
3009  }
3010  }
3011  gboolean showItems = (mainProject->last_loaded >= 0);
3012  gtk_widget_set_sensitive (screen.win.curLayerMenuItem, showItems);
3013  gtk_widget_set_sensitive (screen.win.curAnalyzeMenuItem, showItems);
3014  gtk_widget_set_sensitive (screen.win.curEditMenuItem, showItems);
3015  for (unsigned int i = 0;
3016  i < G_N_ELEMENTS(screen.win.curFileMenuItem); i++) {
3017  gtk_widget_set_sensitive (screen.win.curFileMenuItem[i], showItems);
3018  }
3019  screen.win.treeIsUpdating = FALSE;
3020 }
3021 
3022 /* --------------------------------------------------------------------------- */
3023 void
3024 callbacks_display_object_properties_clicked (GtkButton *button, gpointer user_data)
3025 {
3026  gint index = callbacks_get_selected_row_index ();
3027  guint i;
3028 
3029  if (index < 0 || selection_length (&screen.selectionInfo) == 0) {
3030  interface_show_alert_dialog(_("No object is currently selected"),
3031  _("Objects must be selected using the pointer tool "
3032  "before you can view the object properties."),
3033  FALSE, NULL);
3034  return;
3035  }
3036 
3037  for (i = 0; i < selection_length (&screen.selectionInfo); i++){
3038  gerbv_selection_item_t sItem =
3039  selection_get_item_by_index (&screen.selectionInfo, i);
3040 
3041  gerbv_net_t *net = sItem.net;
3042  gerbv_image_t *image = sItem.image;
3043 
3045  /* Spacing for a pretty display */
3046  if (i != 0)
3047  g_message (" ");
3048 
3049  g_message (_("Object type: Polygon"));
3050  parea_report (net, image, mainProject);
3051  net_layer_file_report (net, image, mainProject);
3052  } else {
3053  switch (net->aperture_state) {
3054 
3057  /* Spacing for a pretty display */
3058  if (i != 0)
3059  g_message (" ");
3060  break;
3061 
3062  default:
3063  break;
3064  }
3065 
3066  aperture_state_report (net, image, mainProject);
3067  }
3068  }
3069  /* Use separator for different report requests */
3070  g_message ("---------------------------------------");
3071 }
3072 
3073 void
3074 callbacks_support_benchmark (gerbv_render_info_t *renderInfo) {
3075  int i;
3076  time_t start, now;
3077  GdkPixmap *renderedPixmap = gdk_pixmap_new (NULL, renderInfo->displayWidth,
3078  renderInfo->displayHeight, 24);
3079 
3080  // start by running the GDK (fast) rendering test
3081  i = 0;
3082  start = time(NULL);
3083  now = start;
3084  while( now - 30 < start) {
3085  i++;
3086  DPRINTF("Benchmark(): Starting redraw #%d\n", i);
3087  gerbv_render_to_pixmap_using_gdk (mainProject, renderedPixmap, renderInfo, NULL, NULL);
3088  now = time(NULL);
3089  DPRINTF("Elapsed time = %ld seconds\n", (long int) (now - start));
3090  }
3091  g_message(_("FAST (=GDK) mode benchmark: %d redraws "
3092  "in %ld seconds (%g redraws/second)"),
3093  i, (long int) (now - start), (double) i / (double)(now - start));
3094  gdk_pixmap_unref(renderedPixmap);
3095 
3096  // run the cairo (normal) render mode
3097  i = 0;
3098  start = time(NULL);
3099  now = start;
3101  while( now - 30 < start) {
3102  i++;
3103  DPRINTF("Benchmark(): Starting redraw #%d\n", i);
3104  cairo_surface_t *cSurface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
3105  renderInfo->displayWidth, renderInfo->displayHeight);
3106  cairo_t *cairoTarget = cairo_create (cSurface);
3107  gerbv_render_all_layers_to_cairo_target (mainProject, cairoTarget, renderInfo);
3108  cairo_destroy (cairoTarget);
3109  cairo_surface_destroy (cSurface);
3110  now = time(NULL);
3111  DPRINTF("Elapsed time = %ld seconds\n", (long int) (now - start));
3112  }
3113  g_message(_("NORMAL (=Cairo) mode benchmark: %d redraws "
3114  "in %ld seconds (%g redraws/second)"),
3115  i, (long int) (now - start), (double) i / (double)(now - start));
3116 }
3117 
3118 /* --------------------------------------------------------------------------- */
3119 void
3120 callbacks_benchmark_clicked (GtkButton *button, gpointer user_data)
3121 {
3122  // prepare render size and options (canvas size width and height are last 2 variables)
3123  gerbv_render_info_t renderInfo = {1.0, 1.0, 0, 0,
3124  GERBV_RENDER_TYPE_GDK, 640, 480};
3125 
3126  if (!interface_get_alert_dialog_response(_("Performance benchmark"),
3127  _("Application will be unresponsive for 1 minute! "
3128  "Run performance benchmark?"),
3129  FALSE, NULL, GTK_STOCK_OK, GTK_STOCK_CANCEL))
3130  return;
3131 
3132  GERB_COMPILE_WARNING(_("Running full zoom benchmark..."));
3133  while (g_main_context_iteration(NULL, FALSE)) {} // update log widget
3134 
3135  // autoscale the image for now...maybe we don't want to do this in order to
3136  // allow benchmarking of different zoom levels?
3138  callbacks_support_benchmark (&renderInfo);
3139 
3140  GERB_COMPILE_WARNING(_("Running x5 zoom benchmark..."));
3141  while (g_main_context_iteration(NULL, FALSE)) {} // update log widget
3142 
3143  renderInfo.lowerLeftX += (screenRenderInfo.displayWidth /
3144  screenRenderInfo.scaleFactorX) / 3.0;
3145  renderInfo.lowerLeftY += (screenRenderInfo.displayHeight /
3146  screenRenderInfo.scaleFactorY) / 3.0;
3147  renderInfo.scaleFactorX *= 5;
3148  renderInfo.scaleFactorY *= 5;
3149  callbacks_support_benchmark (&renderInfo);
3150 }
3151 
3152 /* --------------------------------------------------------------------------- */
3153 void
3154 callbacks_edit_object_properties_clicked (GtkButton *button, gpointer user_data){
3155 }
3156 /* --------------------------------------------------------------------------- */
3157 void
3158 callbacks_live_edit (GtkWidget *button, gpointer user_data){
3159  GtkDialog *toplevel = GTK_DIALOG(gtk_widget_get_toplevel (button));
3160  gtk_dialog_response(toplevel, GTK_RESPONSE_APPLY);
3161 }
3162 /* --------------------------------------------------------------------------- */
3163 void
3164 callbacks_move_objects_clicked (GtkButton *button, gpointer user_data){
3165  /* for testing, just hard code in some translations here */
3166  gerbv_image_move_selected_objects (screen.selectionInfo.selectedNodeArray, -0.050, 0.050);
3167  callbacks_update_layer_tree();
3168  selection_clear (&screen.selectionInfo);
3169  update_selected_object_message (FALSE);
3170  render_refresh_rendered_image_on_screen ();
3171 }
3172 
3173 /* --------------------------------------------------------------------------- */
3174 void
3175 callbacks_reduce_object_area_clicked (GtkButton *button, gpointer user_data){
3176  /* for testing, just hard code in some parameters */
3177  gerbv_image_reduce_area_of_selected_objects (screen.selectionInfo.selectedNodeArray, 0.20, 3, 3, 0.01);
3178  selection_clear (&screen.selectionInfo);
3179  update_selected_object_message (FALSE);
3180  render_refresh_rendered_image_on_screen ();
3181 }
3182 
3183 /* --------------------------------------------------------------------------- */
3184 void
3185 callbacks_delete_objects_clicked (GtkButton *button, gpointer user_data)
3186 {
3187  if (selection_length (&screen.selectionInfo) == 0) {
3189  _("No object is currently selected"),
3190  _("Objects must be selected using the pointer tool "
3191  "before they can be deleted."),
3192  FALSE,
3193  NULL);
3194  return;
3195  }
3196 
3197  gint index = callbacks_get_selected_row_index ();
3198  if (index < 0)
3199  return;
3200 
3203  _("Do you want to permanently delete "
3204  "the selected objects from <i>visible</i> layers?"),
3205  _("Gerbv currently has no undo function, so "
3206  "this action cannot be undone. This action "
3207  "will not change the saved file unless you "
3208  "save the file afterwards."),
3209  TRUE, &(mainProject->check_before_delete),
3210  GTK_STOCK_DELETE, GTK_STOCK_CANCEL)) {
3211  return;
3212  }
3213  }
3214 
3215  guint i;
3216  for (i = 0; i < selection_length (&screen.selectionInfo);) {
3217  gerbv_selection_item_t sel_item =
3218  selection_get_item_by_index (&screen.selectionInfo, i);
3219  gerbv_fileinfo_t *file_info =
3220  gerbv_get_fileinfo_for_image(sel_item.image, mainProject);
3221 
3222  /* Preserve currently invisible selection from deletion */
3223  if (!file_info->isVisible) {
3224  i++;
3225  continue;
3226  }
3227 
3228  file_info->layer_dirty = TRUE;
3229  selection_clear_item_by_index (&screen.selectionInfo, i);
3230  gerbv_image_delete_net (sel_item.net);
3231  }
3232  update_selected_object_message (FALSE);
3233 
3234  render_refresh_rendered_image_on_screen ();
3235  callbacks_update_layer_tree();
3236 }
3237 
3238 /* --------------------------------------------------------------------------- */
3239 gboolean
3240 callbacks_drawingarea_configure_event (GtkWidget *widget, GdkEventConfigure *event)
3241 {
3242  GdkDrawable *drawable = widget->window;
3243 
3244  gdk_drawable_get_size (drawable, &screenRenderInfo.displayWidth, &screenRenderInfo.displayHeight);
3245 
3246  /* set this up if cairo is compiled, since we may need to switch over to
3247  using the surface at any time */
3248  int x_off=0, y_off=0;
3249 
3250  if (GDK_IS_WINDOW(widget->window)) {
3251  /* query the window's backbuffer if it has one */
3252  GdkWindow *window = GDK_WINDOW(widget->window);
3253  gdk_window_get_internal_paint_info (window, &drawable, &x_off, &y_off);
3254  }
3255  if (screen.windowSurface)
3256  cairo_surface_destroy ((cairo_surface_t *)
3257  screen.windowSurface);
3258 
3259 #if defined(WIN32) || defined(QUARTZ)
3260  cairo_t *cairoTarget = gdk_cairo_create (GDK_WINDOW(widget->window));
3261 
3262  screen.windowSurface = cairo_get_target (cairoTarget);
3263  /* increase surface reference by one so it isn't freed when the cairo_t
3264  is destroyed next */
3265  screen.windowSurface = cairo_surface_reference (screen.windowSurface);
3266  cairo_destroy (cairoTarget);
3267 #else
3268  GdkVisual *visual = gdk_drawable_get_visual (drawable);
3269  screen.windowSurface = (gpointer) cairo_xlib_surface_create (GDK_DRAWABLE_XDISPLAY (drawable),
3270  GDK_DRAWABLE_XID (drawable),
3271  GDK_VISUAL_XVISUAL (visual),
3272  screenRenderInfo.displayWidth,
3273  screenRenderInfo.displayHeight);
3274 #endif
3275  /* if this is the first time, go ahead and call autoscale even if we don't
3276  have a model loaded */
3277  if ((screenRenderInfo.scaleFactorX < 0.001)||(screenRenderInfo.scaleFactorY < 0.001)) {
3278  gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
3279  }
3280  render_refresh_rendered_image_on_screen();
3281  return TRUE;
3282 }
3283 
3284 /* --------------------------------------------------------- */
3285 gboolean
3286 callbacks_drawingarea_expose_event (GtkWidget *widget, GdkEventExpose *event)
3287 {
3288  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
3289  GdkPixmap *new_pixmap;
3290  GdkGC *gc = gdk_gc_new(widget->window);
3291 
3292  /*
3293  * Create a pixmap with default background
3294  */
3295  new_pixmap = gdk_pixmap_new(widget->window,
3296  widget->allocation.width,
3297  widget->allocation.height,
3298  -1);
3299 
3300  gdk_gc_set_foreground(gc, &mainProject->background);
3301 
3302  gdk_draw_rectangle(new_pixmap, gc, TRUE,
3303  event->area.x, event->area.y,
3304  event->area.width, event->area.height);
3305 
3306  /*
3307  * Copy gerber pixmap onto background if we have one to copy.
3308  * Do translation at the same time.
3309  */
3310  if (screen.pixmap != NULL) {
3311  gdk_draw_pixmap(new_pixmap,
3312  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
3313  screen.pixmap,
3314  event->area.x - screen.off_x,
3315  event->area.y - screen.off_y,
3316  event->area.x, event->area.y,
3317  event->area.width, event->area.height);
3318  }
3319 
3320  /*
3321  * Draw the whole thing onto screen
3322  */
3323  gdk_draw_pixmap(widget->window,
3324  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
3325  new_pixmap,
3326  event->area.x, event->area.y,
3327  event->area.x, event->area.y,
3328  event->area.width, event->area.height);
3329 
3330  gdk_pixmap_unref(new_pixmap);
3331  gdk_gc_unref(gc);
3332 
3333  /*
3334  * Draw Zooming outline if we are in that mode
3335  */
3336  if (screen.state == IN_ZOOM_OUTLINE) {
3337  render_draw_zoom_outline(screen.centered_outline_zoom);
3338  }
3339  else if (screen.state == IN_MEASURE) {
3341  }
3342  if (screen.tool == MEASURE && screen.state != IN_MEASURE) {
3344  }
3345 
3346  return FALSE;
3347  }
3348 
3349  cairo_t *cr;
3350  int width, height;
3351  int x_off=0, y_off=0;
3352  GdkDrawable *drawable = widget->window;
3353 
3354  if (GDK_IS_WINDOW(widget->window)) {
3355  /* query the window's backbuffer if it has one */
3356  GdkWindow *window = GDK_WINDOW(widget->window);
3357  gdk_window_get_internal_paint_info (window,
3358  &drawable, &x_off, &y_off);
3359  }
3360  gdk_drawable_get_size (drawable, &width, &height);
3361 
3362 #if defined(WIN32) || defined(QUARTZ)
3363  /* FIXME */
3364  cr = gdk_cairo_create (GDK_WINDOW(widget->window));
3365 #else
3366  cairo_surface_t *buffert;
3367 
3368  GdkVisual *visual = gdk_drawable_get_visual (drawable);
3369  buffert = (gpointer) cairo_xlib_surface_create (GDK_DRAWABLE_XDISPLAY (drawable),
3370  GDK_DRAWABLE_XID (drawable),
3371  GDK_VISUAL_XVISUAL (visual),
3372  event->area.width, event->area.height);
3373  cr = cairo_create (buffert);
3374 #endif
3375  cairo_translate (cr, -event->area.x + screen.off_x, -event->area.y + screen.off_y);
3376  render_project_to_cairo_target (cr);
3377  cairo_destroy (cr);
3378 #if !defined(WIN32) && !defined(QUARTZ)
3379  cairo_surface_destroy (buffert);
3380 #endif
3381 
3382  if (screen.tool == MEASURE)
3384  return FALSE;
3385 }
3386 
3387 /* Transforms screen coordinates to board ones */
3388 static void
3389 callbacks_screen2board(gdouble *X, gdouble *Y, gint x, gint y) {
3390 
3391  /* make sure we don't divide by zero (which is possible if the gui
3392  isn't displayed yet */
3393  if ((screenRenderInfo.scaleFactorX > 0.001)||(screenRenderInfo.scaleFactorY > 0.001)) {
3394  *X = screenRenderInfo.lowerLeftX + (x / screenRenderInfo.scaleFactorX);
3395  *Y = screenRenderInfo.lowerLeftY + ((screenRenderInfo.displayHeight - y)
3396  / screenRenderInfo.scaleFactorY);
3397  }
3398  else {
3399  *X = *Y = 0.0;
3400  }
3401 }
3402 
3403 const char *gerbv_coords_pattern_mils_str = N_("%8.2f %8.2f");
3404 
3405 /* --------------------------------------------------------- */
3406 static void
3407 callbacks_update_statusbar_coordinates (gint x, gint y)
3408 {
3409  gdouble X, Y;
3410 
3411  callbacks_screen2board (&X, &Y, x, y);
3412 
3413  switch (screen.unit) {
3414  case GERBV_MILS:
3415  utf8_snprintf (screen.statusbar.coordstr, MAX_COORDLEN,
3416  _(gerbv_coords_pattern_mils_str),
3417  COORD2MILS (X), COORD2MILS (Y));
3418  break;
3419  case GERBV_MMS:
3420  utf8_snprintf (screen.statusbar.coordstr, MAX_COORDLEN,
3421  _("%8.3f %8.3f"),
3422  COORD2MMS (X), COORD2MMS (Y));
3423  break;
3424  default:
3425  utf8_snprintf (screen.statusbar.coordstr, MAX_COORDLEN,
3426  _("%4.5f %4.5f"),
3427  COORD2INS (X), COORD2INS (Y));
3428  }
3429 
3431 }
3432 
3433 static void
3434 update_selected_object_message (gboolean userTriedToSelect)
3435 {
3436  if (screen.tool != POINTER)
3437  return;
3438 
3439  gint selectionLength = selection_length (&screen.selectionInfo);
3440 
3441  if (selectionLength == 0) {
3442  if (userTriedToSelect) {
3443  /* Update status bar message to make sure the user
3444  * knows about needing to select the layer */
3445  gchar *str = g_new(gchar, MAX_DISTLEN);
3446  utf8_strncpy(str,
3447  _("No object selected. Objects can "
3448  "only be selected in the active "
3449  "layer."),
3450  MAX_DISTLEN - 7);
3451  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3452  "<b>%s</b>", str);
3453  g_free(str);
3454  } else {
3455  utf8_strncpy(screen.statusbar.diststr,
3456  _("Click to select objects in the "
3457  "active layer. Middle click and drag "
3458  "to pan."),
3459  MAX_DISTLEN);
3460  }
3461  } else {
3462  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3463  ngettext("%d object are currently selected",
3464  "%d objects are currently selected",
3465  selectionLength), selectionLength);
3466  }
3467 
3469 }
3470 
3471 /* --------------------------------------------------------- */
3472 gboolean
3473 callbacks_drawingarea_motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
3474 {
3475  int x, y;
3476  GdkModifierType state;
3477 
3478  if (event->is_hint)
3479  gdk_window_get_pointer (event->window, &x, &y, &state);
3480  else {
3481  x = event->x;
3482  y = event->y;
3483  state = event->state;
3484  }
3485 
3486  switch (screen.state) {
3487  case IN_MOVE: {
3488  if (screen.last_x != 0 || screen.last_y != 0) {
3489  /* Move pixmap to get a snappier feel of movement */
3490  screen.off_x += x - screen.last_x;
3491  screen.off_y += y - screen.last_y;
3492  }
3493  screenRenderInfo.lowerLeftX -= ((x - screen.last_x) / screenRenderInfo.scaleFactorX);
3494  screenRenderInfo.lowerLeftY += ((y - screen.last_y) / screenRenderInfo.scaleFactorY);
3495  callbacks_force_expose_event_for_screen ();
3496  callbacks_update_scrollbar_positions ();
3497  screen.last_x = x;
3498  screen.last_y = y;
3499  break;
3500  }
3501  case IN_ZOOM_OUTLINE: {
3502  if (screen.last_x || screen.last_y)
3503  render_draw_zoom_outline(screen.centered_outline_zoom);
3504  screen.last_x = x;
3505  screen.last_y = y;
3506  render_draw_zoom_outline(screen.centered_outline_zoom);
3507  break;
3508  }
3509  case IN_MEASURE: {
3510  /* clear the previous drawn line by drawing over it */
3512  callbacks_screen2board(&(screen.measure_stop_x),
3513  &(screen.measure_stop_y), x, y);
3514  /* screen.last_[xy] are updated to move the ruler pointers */
3515  screen.last_x = x;
3516  screen.last_y = y;
3517  /* draw the new line and write the new distance */
3519  break;
3520  }
3521  case IN_SELECTION_DRAG: {
3522  if (screen.last_x || screen.last_y)
3523  render_draw_selection_box_outline();
3524  screen.last_x = x;
3525  screen.last_y = y;
3526  render_draw_selection_box_outline();
3527  break;
3528  }
3529  default:
3530  screen.last_x = x;
3531  screen.last_y = y;
3532  break;
3533  }
3534  callbacks_update_statusbar_coordinates (x, y);
3535  callbacks_update_ruler_pointers ();
3536  return TRUE;
3537 } /* motion_notify_event */
3538 
3539 /* --------------------------------------------------------- */
3540 gboolean
3541 callbacks_drawingarea_button_press_event (GtkWidget *widget, GdkEventButton *event)
3542 {
3543  GdkWindow *drawing_area_window = screen.drawing_area->window;
3544  GdkCursor *cursor;
3545 
3546  switch (event->button) {
3547  case 1 :
3548  if (screen.tool == POINTER) {
3549  /* select */
3550  /* selection will only work with cairo, so do nothing if it's
3551  not compiled */
3552  screen.state = IN_SELECTION_DRAG;
3553  screen.start_x = event->x;
3554  screen.start_y = event->y;
3555  }
3556  else if (screen.tool == PAN) {
3557  /* Plain panning */
3558  screen.state = IN_MOVE;
3559  screen.last_x = event->x;
3560  screen.last_y = event->y;
3561  }
3562  else if (screen.tool == ZOOM) {
3563  screen.state = IN_ZOOM_OUTLINE;
3564  /* Zoom outline mode initiated */
3565  screen.start_x = event->x;
3566  screen.start_y = event->y;
3567  screen.centered_outline_zoom = event->state;
3568  }
3569  else if (screen.tool == MEASURE) {
3570  screen.state = IN_MEASURE;
3571  callbacks_screen2board(&(screen.measure_start_x), &(screen.measure_start_y),
3572  event->x, event->y);
3573  screen.measure_stop_x = screen.measure_start_x;
3574  screen.measure_stop_y = screen.measure_start_y;
3575  /* force an expose event to clear any previous measure lines */
3576  callbacks_force_expose_event_for_screen ();
3577  }
3578  break;
3579  case 2 :
3580  screen.state = IN_MOVE;
3581  screen.last_x = event->x;
3582  screen.last_y = event->y;
3583  cursor = gdk_cursor_new(GDK_FLEUR);
3584  gdk_window_set_cursor(drawing_area_window, cursor);
3585  gdk_cursor_destroy(cursor);
3586  break;
3587  case 3 :
3588  if (screen.tool == POINTER) {
3589  /* if no items are selected, try and find the item the user
3590  is pointing at */
3591  if (selection_length (&screen.selectionInfo) == 0) {
3592  gint index=callbacks_get_selected_row_index();
3593  if ((index >= 0) &&
3594  (index <= mainProject->last_loaded) &&
3595  (mainProject->file[index]->isVisible)) {
3596  render_fill_selection_buffer_from_mouse_click(
3597  event->x, event->y,
3598  index, SELECTION_REPLACE);
3599  } else {
3600  selection_clear (&screen.selectionInfo);
3601  update_selected_object_message (FALSE);
3602  render_refresh_rendered_image_on_screen ();
3603  }
3604  }
3605 
3606  /* only show the popup if we actually have something selected now */
3607  if (selection_length (&screen.selectionInfo) != 0) {
3608  update_selected_object_message (TRUE);
3609  gtk_menu_popup(GTK_MENU(screen.win.drawWindowPopupMenu), NULL, NULL, NULL, NULL,
3610  event->button, event->time);
3611  }
3612 
3613  } else {
3614  /* Zoom outline mode initiated */
3615  screen.state = IN_ZOOM_OUTLINE;
3616  screen.start_x = event->x;
3617  screen.start_y = event->y;
3618  screen.centered_outline_zoom = event->state & GDK_SHIFT_MASK;
3619  cursor = gdk_cursor_new(GDK_SIZING);
3620  gdk_window_set_cursor(drawing_area_window, cursor);
3621  gdk_cursor_destroy(cursor);
3622  }
3623  break;
3624  case 4 : /* Scroll wheel */
3625  render_zoom_display (ZOOM_IN_CMOUSE, 0, event->x, event->y);
3626  break;
3627  case 5 : /* Scroll wheel */
3628  render_zoom_display (ZOOM_OUT_CMOUSE, 0, event->x, event->y);
3629  break;
3630  default:
3631  break;
3632  }
3633  callbacks_switch_to_correct_cursor ();
3634  return TRUE;
3635 }
3636 
3637 static gboolean
3638 check_align_files_possibility (gerbv_selection_info_t *sel_info)
3639 {
3641  GtkMenuItem **menu_items = (GtkMenuItem **) screen.win.curEditAlingItem;
3642  gerbv_selection_item_t si[2];
3643  int id[2] = {-1, -1};
3644  int i;
3645 
3646  /* If has two objects, then can do files aligning */
3647  if (selection_length (sel_info) == 2) {
3648  si[0] = selection_get_item_by_index(sel_info, 0);
3649  si[1] = selection_get_item_by_index(sel_info, 1);
3650 
3651  for (i = 0; i <= mainProject->last_loaded; i++) {
3652  if (f[i]->image == si[0].image)
3653  id[0] = i;
3654 
3655  if (f[i]->image == si[1].image)
3656  id[1] = i;
3657  }
3658 
3659  /* Can align if on different files */
3660  if (id[0]*id[1] >= 0 && id[0] != id[1]) {
3661  gchar *str;
3662 
3663 /* TODO: add color boxes for layers as hint */
3664 
3665  /* Update align menu items */
3666  str = g_strdup_printf (_("#_%i %s > #%i %s"),
3667  id[0]+1, f[id[0]]->name,
3668  id[1]+1, f[id[1]]->name);
3669  gtk_menu_item_set_label (menu_items[0], str);
3670  g_free (str);
3671 
3672  str = g_strdup_printf (_("#_%i %s > #%i %s"),
3673  id[1]+1, f[id[1]]->name,
3674  id[0]+1, f[id[0]]->name);
3675  gtk_menu_item_set_label (menu_items[1], str);
3676  g_free (str);
3677 
3678  gtk_widget_set_sensitive (
3679  screen.win.curEditAlingMenuItem, TRUE);
3680 
3681  return TRUE;
3682  }
3683  }
3684 
3685  /* Can't align, disable align menu */
3686  gtk_widget_set_sensitive (screen.win.curEditAlingMenuItem, FALSE);
3687  gtk_menu_item_set_label (menu_items[0], "");
3688  gtk_menu_item_set_label (menu_items[1], "");
3689 
3690  return FALSE;
3691 }
3692 
3695 void
3697  GtkMenuItem *menu_item, gpointer user_data)
3698 {
3699  gerbv_fileinfo_t *fi[2];
3700  gerbv_selection_item_t item[2];
3701  gerbv_net_t *net;
3702  gerbv_selection_info_t *sel_info = &screen.selectionInfo;
3703  int align_second_to_first = GPOINTER_TO_INT(user_data);
3704  gdouble x[2], y[2];
3705  int i;
3706 
3707  if (selection_length (sel_info) != 2)
3708  return;
3709 
3710  item[0] = selection_get_item_by_index(sel_info, 0);
3711  item[1] = selection_get_item_by_index(sel_info, 1);
3712 
3713  fi[0] = gerbv_get_fileinfo_for_image (item[0].image, mainProject);
3714  fi[1] = gerbv_get_fileinfo_for_image (item[1].image, mainProject);
3715 
3716  if (fi[0] == NULL || fi[1] == NULL || fi[0] == fi[1])
3717  return;
3718 
3719  /* Calculate aligning coords */
3720  for (i = 0; i < 2; i++) {
3721  net = item[i].net;
3722 
3723  switch (net->aperture_state) {
3725  x[i] = net->stop_x;
3726  y[i] = net->stop_y;
3727  break;
3729  switch (net->interpolation) {
3734  x[i] = (net->stop_x + net->start_x)/2;
3735  y[i] = (net->stop_y + net->start_y)/2;
3736  break;
3739  x[i] = net->cirseg->cp_x;
3740  y[i] = net->cirseg->cp_y;
3741  break;
3742  default:
3743  GERB_COMPILE_ERROR (_("Can't align by this "
3744  "type of object"));
3745  return;
3746  }
3747  break;
3748  default:
3749  GERB_COMPILE_ERROR (_("Can't align by this "
3750  "type of object"));
3751  return;
3752  }
3753 
3754  gerbv_transform_coord_for_image(x + i, y + i,
3755  item[i].image, mainProject);
3756  }
3757 
3758  if (align_second_to_first) {
3759  fi[1]->transform.translateX += x[0] - x[1];
3760  fi[1]->transform.translateY += y[0] - y[1];
3761  } else {
3762  fi[0]->transform.translateX += x[1] - x[0];
3763  fi[0]->transform.translateY += y[1] - y[0];
3764  }
3765 
3766  render_refresh_rendered_image_on_screen ();
3767  callbacks_update_layer_tree ();
3768 }
3769 
3770 /* --------------------------------------------------------- */
3771 gboolean
3772 callbacks_drawingarea_button_release_event (GtkWidget *widget, GdkEventButton *event)
3773 {
3774  gint index;
3775 
3776  if (event->type != GDK_BUTTON_RELEASE)
3777  return TRUE;
3778 
3779  switch (screen.state) {
3780  case IN_MOVE:
3781  screen.off_x = 0;
3782  screen.off_y = 0;
3783  render_refresh_rendered_image_on_screen ();
3784  callbacks_switch_to_normal_tool_cursor (screen.tool);
3785  break;
3786 
3787  case IN_ZOOM_OUTLINE:
3788  if ((event->state & GDK_SHIFT_MASK) != 0) {
3789  render_zoom_display (ZOOM_OUT_CMOUSE, 0,
3790  event->x, event->y);
3791  }
3792  /* if the user just clicks without dragging, then simply
3793  zoom in a preset amount */
3795  else if ((fabs(screen.start_x - event->x) < 4.0) &&
3796  (fabs(screen.start_y - event->y) < 4.0)) {
3797  render_zoom_display (ZOOM_IN_CMOUSE, 0,
3798  event->x, event->y);
3799  } else {
3800  render_calculate_zoom_from_outline (widget, event);
3801  }
3802  callbacks_switch_to_normal_tool_cursor (screen.tool);
3803  break;
3804 
3805  case IN_SELECTION_DRAG:
3806  /* selection will only work with cairo, so do nothing if it's
3807  not compiled */
3809 
3810  if ((index >= 0) && mainProject->file[index]->isVisible) {
3811  enum selection_action sel_action = SELECTION_REPLACE;
3812 
3813  if (event->state & GDK_SHIFT_MASK)
3814  sel_action = SELECTION_ADD;
3815  else if (event->state & GDK_CONTROL_MASK)
3816  sel_action = SELECTION_TOGGLE;
3817 
3818  /* determine if this was just a click or a box drag */
3819  if ((fabs((double)(screen.last_x - screen.start_x)) < 5)
3820  && (fabs((double)(screen.last_y - screen.start_y)) < 5)) {
3821  render_fill_selection_buffer_from_mouse_click (
3822  event->x, event->y, index,
3823  sel_action);
3824  } else {
3825  render_fill_selection_buffer_from_mouse_drag (
3826  event->x, event->y,
3827  screen.start_x, screen.start_y,
3828  index, sel_action);
3829  }
3830 
3831  /* Check if anything was selected */
3832  update_selected_object_message (TRUE);
3833 
3834  check_align_files_possibility (&screen.selectionInfo);
3835  } else {
3836  render_refresh_rendered_image_on_screen ();
3837  }
3838  break;
3839  default:
3840  break;
3841  }
3842 
3843  screen.state = NORMAL;
3844 
3845  return TRUE;
3846 } /* button_release_event */
3847 
3848 /* --------------------------------------------------------- */
3849 gboolean
3850 callbacks_window_key_press_event (GtkWidget *widget, GdkEventKey *event)
3851 {
3852  switch (event->keyval) {
3853  case GDK_Escape:
3854  if (screen.tool == POINTER) {
3855  selection_clear (&screen.selectionInfo);
3856  update_selected_object_message (FALSE);
3857  }
3858 
3859  /* Escape may be used to abort outline zoom and just plain
3860  * repaint */
3861  screen.state = NORMAL;
3862  render_refresh_rendered_image_on_screen();
3863 
3864  break;
3865  default:
3866  break;
3867  }
3868 
3869  return TRUE;
3870 } /* key_press_event */
3871 
3872 /* --------------------------------------------------------- */
3873 gboolean
3874 callbacks_window_key_release_event (GtkWidget *widget, GdkEventKey *event)
3875 {
3876  return TRUE;
3877 } /* key_release_event */
3878 
3879 /* --------------------------------------------------------- */
3880 /* Scroll wheel */
3881 gboolean
3882 callbacks_window_scroll_event(GtkWidget *widget, GdkEventScroll *event)
3883 {
3884  switch (event->direction) {
3885  case GDK_SCROLL_UP:
3886  render_zoom_display (ZOOM_IN_CMOUSE, 0, event->x, event->y);
3887  break;
3888  case GDK_SCROLL_DOWN:
3889  render_zoom_display (ZOOM_OUT_CMOUSE, 0, event->x, event->y);
3890  break;
3891  case GDK_SCROLL_LEFT:
3892  /* Ignore */
3893  case GDK_SCROLL_RIGHT:
3894  /* Ignore */
3895  default:
3896  return TRUE;
3897  }
3898  return TRUE;
3899 } /* scroll_event */
3900 
3901 
3902 /* ------------------------------------------------------------------ */
3909 void
3911 {
3912  if (GTK_IS_LABEL(screen.win.statusMessageLeft)) {
3913  gtk_label_set_text(GTK_LABEL(screen.win.statusMessageLeft), screen.statusbar.coordstr);
3914  }
3915  if (GTK_IS_LABEL(screen.win.statusMessageRight)) {
3916  gtk_label_set_markup(GTK_LABEL(screen.win.statusMessageRight), screen.statusbar.diststr);
3917  }
3918 }
3919 
3920 /* --------------------------------------------------------- */
3921 void
3922 callbacks_update_statusbar_measured_distance (gdouble dx, gdouble dy){
3923  gdouble delta = hypot(dx, dy);
3924 
3925  if (screen.unit == GERBV_MILS) {
3926  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3927  _("Measured distance: %8.2f mils (%8.2f x, %8.2f y)"),
3928  COORD2MILS(delta), COORD2MILS(dx), COORD2MILS(dy));
3929  }
3930  else if (screen.unit == GERBV_MMS) {
3931  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3932  _("Measured distance: %8.3f mm (%8.3f x, %8.3f y)"),
3933  COORD2MMS(delta), COORD2MMS(dx), COORD2MMS(dy));
3934  }
3935  else {
3936  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3937  _("Measured distance: %4.5f inches (%4.5f x, %4.5f y)"),
3938  COORD2INS(delta), COORD2INS(dx), COORD2INS(dy));
3939  }
3941 }
3942 
3943 /* --------------------------------------------------------- */
3944 void
3945 callbacks_sidepane_render_type_combo_box_changed (GtkComboBox *widget, gpointer user_data) {
3946  gerbv_render_types_t type = gtk_combo_box_get_active (widget);
3947 
3948  DPRINTF("%s(): type = %d\n", __FUNCTION__, type);
3949 
3950  if (type < 0 || type == screenRenderInfo.renderType)
3951  return;
3952 
3953  screenRenderInfo.renderType = type;
3954  callbacks_render_type_changed ();
3955 }
3956 
3957 /* --------------------------------------------------------- */
3958 void
3959 callbacks_viewmenu_rendertype_changed (GtkCheckMenuItem *widget, gpointer user_data) {
3960  gerbv_render_types_t type = GPOINTER_TO_INT(user_data);
3961 
3962  if (type == screenRenderInfo.renderType)
3963  return;
3964 
3965  DPRINTF("%s(): type = %d\n", __FUNCTION__, type);
3966 
3967  screenRenderInfo.renderType = type;
3968  callbacks_render_type_changed ();
3969 }
3970 
3971 /* --------------------------------------------------------- */
3972 void
3973 callbacks_viewmenu_units_changed (GtkCheckMenuItem *widget, gpointer user_data) {
3974  gerbv_gui_unit_t unit = GPOINTER_TO_INT(user_data);
3975 
3976  if (unit < 0 || unit == screen.unit)
3977  return;
3978 
3979  DPRINTF("%s(): unit = %d, screen.unit = %d\n", __FUNCTION__, unit, screen.unit);
3980 
3981  callbacks_units_changed (unit);
3982 }
3983 
3984 /* --------------------------------------------------------- */
3985 void
3986 callbacks_statusbar_unit_combo_box_changed (GtkComboBox *widget, gpointer user_data) {
3987  gerbv_gui_unit_t unit = gtk_combo_box_get_active (widget);
3988  int force_change = GPOINTER_TO_INT (user_data);
3989 
3990  if (!force_change && (unit < 0 || unit == screen.unit))
3991  return;
3992 
3993  callbacks_units_changed (unit);
3994 }
3995 
3996 /* --------------------------------------------------------- */
3997 void
3998 callbacks_clear_messages_button_clicked (GtkButton *button, gpointer user_data) {
3999  GtkTextBuffer *textbuffer;
4000  GtkTextIter start, end;
4001 
4002  screen.length_sum = 0;
4003 
4004  textbuffer = gtk_text_view_get_buffer((GtkTextView*)screen.win.messageTextView);
4005  gtk_text_buffer_get_start_iter(textbuffer, &start);
4006  gtk_text_buffer_get_end_iter(textbuffer, &end);
4007  gtk_text_buffer_delete (textbuffer, &start, &end);
4008 }
4009 
4010 /* --------------------------------------------------------- */
4011 void
4012 callbacks_handle_log_messages(const gchar *log_domain, GLogLevelFlags log_level,
4013  const gchar *message, gpointer user_data)
4014 {
4015  GtkTextBuffer *textbuffer = NULL;
4016  GtkTextIter iter;
4017  GtkTextTag *tag;
4018  GtkTextMark *StartMark = NULL, *StopMark = NULL;
4019  GtkTextIter StartIter, StopIter;
4020  GtkWidget *dialog, *label;
4021 
4022  if (!screen.win.messageTextView)
4023  return;
4024 
4025  textbuffer = gtk_text_view_get_buffer((GtkTextView*)screen.win.messageTextView);
4026 
4027  /* create a mark for the end of the text. */
4028  gtk_text_buffer_get_end_iter(textbuffer, &iter);
4029 
4030  /* get the current end position of the text (it will be the
4031  start of the new text. */
4032  StartMark = gtk_text_buffer_create_mark(textbuffer,
4033  "NewTextStart", &iter, TRUE);
4034 
4035  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
4036  "blue_foreground");
4037  /* the tag does not exist: create it and let them exist in the tag table.*/
4038  if (tag == NULL) {
4039  tag = gtk_text_buffer_create_tag(textbuffer, "black_foreground",
4040  "foreground", "black", NULL);
4041  tag = gtk_text_buffer_create_tag(textbuffer, "blue_foreground",
4042  "foreground", "blue", NULL);
4043  tag = gtk_text_buffer_create_tag(textbuffer, "red_foreground",
4044  "foreground", "red", NULL);
4045  tag = gtk_text_buffer_create_tag(textbuffer, "darkred_foreground",
4046  "foreground", "darkred", NULL);
4047  tag = gtk_text_buffer_create_tag(textbuffer, "darkblue_foreground",
4048  "foreground", "darkblue", NULL);
4049  tag = gtk_text_buffer_create_tag (textbuffer, "darkgreen_foreground",
4050  "foreground", "darkgreen", NULL);
4051  tag = gtk_text_buffer_create_tag (textbuffer,
4052  "saddlebrown_foreground",
4053  "foreground", "saddlebrown", NULL);
4054  }
4055 
4056  /*
4057  * See rgb.txt for the color names definition
4058  * (on my PC it is on /usr/X11R6/lib/X11/rgb.txt)
4059  */
4060  switch (log_level & G_LOG_LEVEL_MASK) {
4061  case G_LOG_LEVEL_ERROR:
4062  /* a message of this kind aborts the application calling abort() */
4063  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
4064  "red_foreground");
4065  gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
4066  gtk_widget_show(screen.win.sidepane_notebook);
4067  break;
4068  case G_LOG_LEVEL_CRITICAL:
4069  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
4070  "red_foreground");
4071  gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
4072  gtk_widget_show(screen.win.sidepane_notebook);
4073  break;
4074  case G_LOG_LEVEL_WARNING:
4075  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
4076  "darkred_foreground");
4077  gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
4078  gtk_widget_show(screen.win.sidepane_notebook);
4079  break;
4080  case G_LOG_LEVEL_MESSAGE:
4081  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
4082  "darkblue_foreground");
4083  gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
4084  gtk_widget_show(screen.win.sidepane_notebook);
4085  break;
4086  case G_LOG_LEVEL_INFO:
4087  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
4088  "darkgreen_foreground");
4089  break;
4090  case G_LOG_LEVEL_DEBUG:
4091  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
4092  "saddlebrown_foreground");
4093  break;
4094  default:
4095  tag = gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table(textbuffer),
4096  "black_foreground");
4097  break;
4098  }
4099 
4100  /*
4101  * Fatal aborts application. We will try to get the message out anyhow.
4102  */
4103  if (log_level & G_LOG_FLAG_FATAL) {
4104  fprintf(stderr, _("Fatal error: %s\n"), message);
4105 
4106  /* Try to show dialog box with error message */
4107  dialog = gtk_dialog_new_with_buttons(_("Fatal Error"),
4108  NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4109  GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
4110 
4111  label = gtk_label_new(g_strdup_printf(_("Fatal error: %s"), message));
4112  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),
4113  label);
4114  gtk_label_set_selectable(GTK_LABEL(label), TRUE);
4115  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),
4116  gtk_label_new(_("\nGerbv will be closed now!")));
4117 
4118  gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
4119 
4120  gtk_widget_show_all(dialog);
4121  gtk_dialog_run(GTK_DIALOG(dialog));
4122  }
4123 
4124  gtk_text_buffer_insert(textbuffer, &iter, message, -1);
4125  gtk_text_buffer_insert(textbuffer, &iter, "\n", -1);
4126 
4127  /* Scroll view to inserted text */
4128  g_signal_emit_by_name(textbuffer, "paste-done", NULL);
4129 
4130  gtk_text_buffer_get_end_iter(textbuffer, &iter);
4131 
4132  StopMark = gtk_text_buffer_create_mark(textbuffer,
4133  "NewTextStop", &iter, TRUE);
4134 
4135  gtk_text_buffer_get_iter_at_mark(textbuffer, &StartIter, StartMark);
4136  gtk_text_buffer_get_iter_at_mark(textbuffer, &StopIter, StopMark);
4137 
4138  gtk_text_buffer_apply_tag(textbuffer, tag, &StartIter, &StopIter);
4139 }
4140 
4141 /* --------------------------------------------------------- */
4142 void callbacks_force_expose_event_for_screen (void)
4143 {
4144  GdkRectangle update_rect;
4145 
4146  update_rect.x = 0;
4147  update_rect.y = 0;
4148  update_rect.width = screenRenderInfo.displayWidth;
4149  update_rect.height = screenRenderInfo.displayHeight;
4150 
4151  /* Calls expose_event */
4152  gdk_window_invalidate_rect (screen.drawing_area->window, &update_rect, FALSE);
4153 
4154  /* update other gui things that could have changed */
4155  callbacks_update_ruler_scales ();
4156  callbacks_update_scrollbar_limits ();
4157  callbacks_update_scrollbar_positions ();
4158 }
4159 
4160 static double screen_units(double d)
4161 {
4162  switch (screen.unit) {
4163  case GERBV_INS:
4164  return COORD2INS(d);
4165  break;
4166  case GERBV_MILS:
4167  return COORD2MILS(d);
4168  break;
4169  case GERBV_MMS:
4170  return COORD2MMS(d);
4171  break;
4172  }
4173 
4174  return d;
4175 }
4176 
4177 static const char *screen_units_str(void)
4178 {
4179  /* NOTE: in order of gerbv_gui_unit_t */
4180  const char *units_str[] = {N_("mil"), N_("mm"), N_("in")};
4181 
4182  return _(units_str[screen.unit]);
4183 }
4184 
4185 static double line_length(double x0, double y0, double x1, double y1)
4186 {
4187  double dx = x0 - x1;
4188  double dy = y0 - y1;
4189 
4190  return hypot(dx, dy);
4191 }
4192 
4193 static double arc_length(double dia, double angle)
4194 {
4195  return M_PI*dia*(angle/360.0);
4196 }
4197 
4198 static void aperture_state_report (gerbv_net_t *net,
4199  gerbv_image_t *img, gerbv_project_t *prj)
4200 {
4201  gerbv_layertype_t layer_type = img->layertype;
4202 
4203  gboolean show_length = FALSE;
4204  gboolean aperture_is_valid = FALSE;
4205  double x, y, len = 0;
4206 
4207  if (net->aperture > 0)
4208  aperture_is_valid = TRUE;
4209 
4210  switch (net->aperture_state) {
4211 
4213  break;
4214 
4216  switch (net->interpolation) {
4217 
4222  if (layer_type != GERBV_LAYERTYPE_DRILL)
4223  g_message (_("Object type: Line"));
4224  else
4225  g_message (_("Object type: Slot (drilled)"));
4226 
4227  len = line_length(net->start_x, net->start_y,
4228  net->stop_x, net->stop_y);
4229  show_length = 1;
4230 
4231  break;
4232 
4235  g_message (_("Object type: Arc"));
4236  len = arc_length(net->cirseg->width,
4237  fabs(net->cirseg->angle1 -
4238  net->cirseg->angle2));
4239  show_length = 1;
4240 
4241  break;
4242  default:
4243  g_message (_("Object type: Unknown"));
4244  break;
4245  }
4246 
4247  if (layer_type != GERBV_LAYERTYPE_DRILL)
4248  g_message (_(" Exposure: On"));
4249 
4250  if (aperture_is_valid) {
4251  if (layer_type != GERBV_LAYERTYPE_DRILL)
4252  aperture_report(img->aperture, net->aperture,
4253  net->start_x, net->start_y,
4254  img, prj);
4255  else
4256  drill_report(img->aperture, net->aperture);
4257  }
4258 
4259  x = net->start_x;
4260  y = net->start_y;
4261  gerbv_transform_coord_for_image(&x, &y, img, prj);
4262  g_message (_(" Start: (%g, %g) %s"),
4263  screen_units(x),
4264  screen_units(y),
4265  screen_units_str());
4266 
4267  x = net->stop_x;
4268  y = net->stop_y;
4269  gerbv_transform_coord_for_image(&x, &y, img, prj);
4270  g_message (_(" Stop: (%g, %g) %s"),
4271  screen_units(x),
4272  screen_units(y),
4273  screen_units_str());
4274 
4275  switch (net->interpolation) {
4276 
4279  x = net->cirseg->cp_x;
4280  y = net->cirseg->cp_y;
4281  gerbv_transform_coord_for_image(&x, &y, img, prj);
4282  g_message (_(" Center: (%g, %g) %s"),
4283  screen_units(x),
4284  screen_units(y),
4285  screen_units_str());
4286 
4287  x = net->cirseg->width/2;
4288  y = x;
4289  gerbv_transform_coord_for_image(&x, &y, img, prj);
4290  g_message (_(" Radius: %g %s"),
4291  screen_units(x),
4292  screen_units_str());
4293 
4294  g_message (_(" Angle: %g deg"),
4295  fabs(net->cirseg->angle1 -
4296  net->cirseg->angle2));
4297  g_message (_(" Angles: (%g, %g) deg"),
4298  net->cirseg->angle1,
4299  net->cirseg->angle2);
4300  g_message (_(" Direction: %s"),
4301  (net->interpolation ==
4303  _("CW"): _("CCW"));
4304  break;
4305 
4306  default:
4307  break;
4308  }
4309 
4310  if (show_length) {
4311  gerbv_aperture_t *aper = img->aperture[net->aperture];
4312 
4313  if (layer_type == GERBV_LAYERTYPE_DRILL
4314  && aperture_is_valid
4315  && aper->type == GERBV_APTYPE_CIRCLE) {
4316  double dia = aper->parameter[0];
4317  g_message (_(" Slot length: %g %s"),
4318  screen_units(len + dia),
4319  screen_units_str());
4320  }
4321 
4322  screen.length_sum += len;
4323  g_message (_(" Length: %g (sum: %g) %s"),
4324  screen_units(len),
4325  screen_units(screen.length_sum),
4326  screen_units_str());
4327  }
4328 
4329  net_layer_file_report (net, img, prj);
4330 
4331  break;
4332 
4334  if (layer_type != GERBV_LAYERTYPE_DRILL)
4335  g_message (_("Object type: Flashed aperture"));
4336  else
4337  g_message (_("Object type: Drill"));
4338 
4339  if (aperture_is_valid) {
4340  if (layer_type != GERBV_LAYERTYPE_DRILL)
4341  aperture_report(img->aperture, net->aperture,
4342  net->stop_x, net->stop_y,
4343  img, prj);
4344  else
4345  drill_report(img->aperture, net->aperture);
4346  }
4347 
4348  x = net->stop_x;
4349  y = net->stop_y;
4350  gerbv_transform_coord_for_image(&x, &y, img, prj);
4351  g_message (_(" Location: (%g, %g) %s"),
4352  screen_units(x),
4353  screen_units(y),
4354  screen_units_str());
4355 
4356  net_layer_file_report (net, img, prj);
4357 
4358  break;
4359  }
4360 }
4361 
4362 static void
4363 aperture_report(gerbv_aperture_t *apertures[], int aperture_num,
4364  double x, double y, gerbv_image_t *img, gerbv_project_t *prj)
4365 {
4366  gerbv_aperture_type_t type = apertures[aperture_num]->type;
4367  double *params = apertures[aperture_num]->parameter;
4368  gerbv_simplified_amacro_t *sam = apertures[aperture_num]->simplified;
4369 
4370  g_message (_(" Aperture used: D%d"), aperture_num);
4371  g_message (_(" Aperture type: %s"),
4372  (type == GERBV_APTYPE_MACRO)?
4373  _(gerbv_aperture_type_name(sam->type)):
4374  _(gerbv_aperture_type_name(type)));
4375 
4376  switch (type) {
4377  case GERBV_APTYPE_CIRCLE:
4378  g_message (_(" Diameter: %g %s"),
4379  screen_units(params[0]),
4380  screen_units_str());
4381  break;
4383  case GERBV_APTYPE_OVAL:
4384  g_message (_(" Dimensions: %gx%g %s"),
4385  screen_units(params[0]),
4386  screen_units(params[1]),
4387  screen_units_str());
4388  break;
4389  case GERBV_APTYPE_MACRO: {
4390  switch (sam->type) {
4392  g_message (_(" Diameter: %g %s"),
4393  screen_units(sam->parameter[CIRCLE_DIAMETER]),
4394  screen_units_str());
4395  x += sam->parameter[CIRCLE_CENTER_X];
4396  y += sam->parameter[CIRCLE_CENTER_Y];
4397  gerbv_transform_coord_for_image(&x, &y, img, prj);
4398  g_message (_(" Center: (%g, %g) %s"),
4399  screen_units(x), screen_units(y),
4400  screen_units_str());
4401  break;
4402 
4404  g_message (_(" Number of points: %g"),
4405  sam->parameter[OUTLINE_NUMBER_OF_POINTS]);
4406  x += sam->parameter[OUTLINE_FIRST_X];
4407  y += sam->parameter[OUTLINE_FIRST_Y];
4408  gerbv_transform_coord_for_image(&x, &y, img, prj);
4409  g_message (_(" Start: (%g, %g) %s"),
4410  screen_units(x), screen_units(y),
4411  screen_units_str());
4412  g_message (_(" Rotation: %g deg"),
4413  sam->parameter[OUTLINE_ROTATION_IDX(sam->parameter)]);
4414  break;
4415 
4417  g_message (_(" Number of points: %g"),
4418  sam->parameter[POLYGON_NUMBER_OF_POINTS]);
4419  g_message (_(" Diameter: %g %s"),
4420  screen_units(sam->parameter[POLYGON_DIAMETER]),
4421  screen_units_str());
4422  x += sam->parameter[POLYGON_CENTER_X];
4423  y += sam->parameter[POLYGON_CENTER_Y];
4424  gerbv_transform_coord_for_image(&x, &y, img, prj);
4425  g_message (_(" Center: (%g, %g) %s"),
4426  screen_units(x), screen_units(y),
4427  screen_units_str());
4428  g_message (_(" Rotation: %g deg"),
4429  sam->parameter[POLYGON_ROTATION]);
4430  break;
4431 
4433  g_message (_(" Outside diameter: %g %s"),
4434  screen_units(sam->parameter[MOIRE_OUTSIDE_DIAMETER]),
4435  screen_units_str());
4436  g_message (_(" Ring thickness: %g %s"),
4437  screen_units(sam->parameter[MOIRE_CIRCLE_THICKNESS]),
4438  screen_units_str());
4439  g_message (_(" Gap width: %g %s"),
4440  screen_units(sam->parameter[MOIRE_GAP_WIDTH]),
4441  screen_units_str());
4442  g_message (_(" Number of rings: %g"),
4443  sam->parameter[MOIRE_NUMBER_OF_CIRCLES]);
4444  g_message (_(" Crosshair thickness: %g %s"),
4445  screen_units(
4446  sam->parameter[MOIRE_CROSSHAIR_THICKNESS]),
4447  screen_units_str());
4448  g_message (_(" Crosshair length: %g %s"),
4449  screen_units(sam->parameter[MOIRE_CROSSHAIR_LENGTH]),
4450  screen_units_str());
4451  x += sam->parameter[MOIRE_CENTER_X];
4452  y += sam->parameter[MOIRE_CENTER_Y];
4453  gerbv_transform_coord_for_image(&x, &y, img, prj);
4454  g_message (_(" Center: (%g, %g) %s"),
4455  screen_units(x), screen_units(y),
4456  screen_units_str());
4457  g_message (_(" Rotation: %g deg"),
4458  sam->parameter[MOIRE_ROTATION]);
4459  break;
4460 
4462  g_message (_(" Outside diameter: %g %s"),
4463  screen_units(sam->parameter[THERMAL_OUTSIDE_DIAMETER]),
4464  screen_units_str());
4465  g_message (_(" Inside diameter: %g %s"),
4466  screen_units(sam->parameter[THERMAL_INSIDE_DIAMETER]),
4467  screen_units_str());
4468  g_message (_(" Crosshair thickness: %g %s"),
4469  screen_units(
4470  sam->parameter[THERMAL_CROSSHAIR_THICKNESS]),
4471  screen_units_str());
4472  x += sam->parameter[THERMAL_CENTER_X];
4473  y += sam->parameter[THERMAL_CENTER_Y];
4474  gerbv_transform_coord_for_image(&x, &y, img, prj);
4475  g_message (_(" Center: (%g, %g) %s"),
4476  screen_units(x), screen_units(y),
4477  screen_units_str());
4478  g_message (_(" Rotation: %g deg"),
4479  sam->parameter[THERMAL_ROTATION]);
4480  break;
4481 
4483  g_message (_(" Width: %g %s"),
4484  screen_units(sam->parameter[LINE20_WIDTH]),
4485  screen_units_str());
4486  x += sam->parameter[LINE20_START_X];
4487  y += sam->parameter[LINE20_START_Y];
4488  gerbv_transform_coord_for_image(&x, &y, img, prj);
4489  g_message (_(" Start: (%g, %g) %s"),
4490  screen_units(x), screen_units(y),
4491  screen_units_str());
4492  x += sam->parameter[LINE20_END_X];
4493  y += sam->parameter[LINE20_END_Y];
4494  gerbv_transform_coord_for_image(&x, &y, img, prj);
4495  g_message (_(" Stop: (%g, %g) %s"),
4496  screen_units(x), screen_units(y),
4497  screen_units_str());
4498  g_message (_(" Rotation: %g deg"),
4499  sam->parameter[LINE20_ROTATION]);
4500  break;
4501 
4503  g_message (_(" Width: %g %s"),
4504  screen_units(sam->parameter[LINE21_WIDTH]),
4505  screen_units_str());
4506  g_message (_(" Height: %g %s"),
4507  screen_units(sam->parameter[LINE21_HEIGHT]),
4508  screen_units_str());
4509  x += sam->parameter[LINE21_CENTER_X];
4510  y += sam->parameter[LINE21_CENTER_Y];
4511  gerbv_transform_coord_for_image(&x, &y, img, prj);
4512  g_message (_(" Center: (%g, %g) %s"),
4513  screen_units(x), screen_units(y),
4514  screen_units_str());
4515  g_message (_(" Rotation: %g deg"),
4516  sam->parameter[LINE21_ROTATION]);
4517  break;
4518 
4520  g_message (_(" Width: %g %s"),
4521  screen_units(sam->parameter[LINE22_WIDTH]),
4522  screen_units_str());
4523  g_message (_(" Height: %g %s"),
4524  screen_units(sam->parameter[LINE22_HEIGHT]),
4525  screen_units_str());
4526  x += sam->parameter[LINE22_LOWER_LEFT_X];
4527  y += sam->parameter[LINE22_LOWER_LEFT_Y];
4528  gerbv_transform_coord_for_image(&x, &y, img, prj);
4529  g_message (_(" Lower left: (%g, %g) %s"),
4530  screen_units(x), screen_units(y),
4531  screen_units_str());
4532  g_message (_(" Rotation: %g deg"),
4533  sam->parameter[LINE22_ROTATION]);
4534  break;
4535 
4536  default:
4537  break;
4538  }
4539  break;
4540  }
4541  default:
4542  break;
4543  }
4544 }
4545 
4546 static void drill_report(gerbv_aperture_t *apertures[], int aperture_num)
4547 {
4548  gerbv_aperture_type_t type = apertures[aperture_num]->type;
4549  double *params = apertures[aperture_num]->parameter;
4550 
4551  g_message (_(" Tool used: T%d"), aperture_num);
4552  if (type == GERBV_APTYPE_CIRCLE)
4553  g_message (_(" Diameter: %g %s"),
4554  screen_units(params[0]),
4555  screen_units_str());
4556 }
4557 
4558 static void parea_report (gerbv_net_t *net,
4559  gerbv_image_t *img, gerbv_project_t *prj)
4560 {
4561  gerbv_net_t *n;
4562  unsigned int c = 0;
4563  gerbv_interpolation_t inter_prev;
4564  double x, y;
4565 
4567  return;
4568 
4569  /* Count vertices */
4570  for (gerbv_net_t *n = net->next; n != NULL; n = n->next) {
4572  break;
4573  c++;
4574  }
4575 
4576  g_message (_(" Number of vertices: %u"), c - 1);
4577 
4578  for (n = net->next, inter_prev = net->interpolation;
4579  n != NULL
4581  n = n->next) {
4582 
4583  switch (n->interpolation) {
4584 
4586 
4587  if (inter_prev != n->interpolation) {
4588  x = n->start_x;
4589  y = n->start_y;
4591  img, prj);
4592  g_message (_(" Line from: (%g, %g) %s"),
4593  screen_units(x),
4594  screen_units(y),
4595  screen_units_str());
4596  }
4597 
4598  x = n->stop_x;
4599  y = n->stop_y;
4600  gerbv_transform_coord_for_image(&x, &y, img, prj);
4601  g_message (_(" Line to: (%g, %g) %s"),
4602  screen_units(x), screen_units(y),
4603  screen_units_str());
4604  break;
4605 
4608 
4609  x = n->start_x;
4610  y = n->start_y;
4611  gerbv_transform_coord_for_image(&x, &y, img, prj);
4612  g_message (_(" Arc from: (%g, %g) %s"),
4613  screen_units(x), screen_units(y),
4614  screen_units_str());
4615 
4616  x = n->stop_x;
4617  y = n->stop_y;
4618  gerbv_transform_coord_for_image(&x, &y, img, prj);
4619  g_message (_(" Arc to: (%g, %g) %s"),
4620  screen_units(x), screen_units(y),
4621  screen_units_str());
4622 
4623  x = n->cirseg->cp_x;
4624  y = n->cirseg->cp_y;
4625  gerbv_transform_coord_for_image(&x, &y, img, prj);
4626  g_message (_(" Center: (%g, %g) %s"),
4627  screen_units(x), screen_units(y),
4628  screen_units_str());
4629 
4630  x = n->cirseg->width;
4631  y = n->cirseg->height;
4632  gerbv_transform_coord_for_image(&x, &y, img, prj);
4633  g_message (_(" Radius: %g %s"),
4634  screen_units(x)/2, screen_units_str());
4635 
4636  g_message (_(" Angle: %g deg"),
4637  fabs(n->cirseg->angle1 - n->cirseg->angle2));
4638  g_message (_(" Angles: (%g, %g) deg"),
4639  n->cirseg->angle1, n->cirseg->angle2);
4640  g_message (_(" Direction: %s"),
4641  (n->interpolation ==
4643  _("CW"): _("CCW"));
4644  break;
4645 
4646  default:
4647  g_message(" Skipping interpolation: %s",
4649  }
4650 
4651  inter_prev = n->interpolation;
4652  }
4653 }
4654 
4655 static void net_layer_file_report(gerbv_net_t *net,
4656  gerbv_image_t *img, gerbv_project_t *prj)
4657 {
4658  /* Don't report "no net" to keep log short */
4659  if (net->label != NULL)
4660  g_message (_(" Net label: %s"), net->label->str);
4661 
4662  /* Don't report "no layer name" to keep log short */
4663  if (net->layer->name != NULL)
4664  g_message (_(" Layer name: %s"), net->layer->name);
4665 
4666  /* Search file name in project files array */
4667  for (int i = 0; i <= prj->last_loaded; i++) {
4668  if (img == prj->file[i]->image)
4669  g_message (_(" In file: %s"), prj->file[i]->name);
4670  }
4671 }
4672 
4673 /* Restore report window size and postion */
4674 static void
4675 analyze_window_size_restore(GtkWidget *win)
4676 {
4677  GVariant *var;
4678  const gint32 *xy;
4679  gsize num;
4680 
4681  if (!screen.settings)
4682  return;
4683 
4684  var = g_settings_get_value (screen.settings, "analyze-window-size");
4685  xy = g_variant_get_fixed_array (var, &num, sizeof (*xy));
4686  if (num == 2)
4687  gtk_window_set_default_size (GTK_WINDOW (win), xy[0], xy[1]);
4688  g_variant_unref (var);
4689 
4690  var = g_settings_get_value (screen.settings, "analyze-window-position");
4691  xy = g_variant_get_fixed_array (var, &num, sizeof (*xy));
4692  if (num == 2)
4693  gtk_window_move (GTK_WINDOW (win), xy[0], xy[1]);
4694  g_variant_unref (var);
4695 }
4696 
4697 /* Store report window size and postion */
4698 static void
4699 analyze_window_size_store(GtkWidget *win, gpointer user_data)
4700 {
4701  gint32 xy[2];
4702  GVariant *var;
4703  gboolean is_max;
4704 
4705  if (!screen.settings)
4706  return;
4707 
4708  is_max = FALSE != (GDK_WINDOW_STATE_MAXIMIZED &
4709  gdk_window_get_state (gtk_widget_get_window (win)));
4710  if (is_max)
4711  return;
4712 
4713  gtk_window_get_size (GTK_WINDOW (win), (gint *)xy, (gint *)(xy+1));
4714  var = g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
4715  xy, 2, sizeof (xy[0]));
4716  g_settings_set_value (screen.settings, "analyze-window-size", var);
4717 
4718  gtk_window_get_position (GTK_WINDOW (win),
4719  (gint *)xy, (gint *)(xy+1));
4720  var = g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
4721  xy, 2, sizeof (xy[0]));
4722  g_settings_set_value (screen.settings, "analyze-window-position", var);
4723 }
Dynamic GUI window creation header info.
void open_files(GSList *filenames)
File -> open action requested or file drop event happened.
Definition: callbacks.c:218
void callbacks_bugs_activate(GtkMenuItem *menuitem, gpointer user_data)
The help -> bugs menu item was selected.
Definition: callbacks.c:1986
gboolean callbacks_quit_activate(GtkMenuItem *menuitem, gpointer user_data)
The file -> quit menu item was selected or the user requested the main window to be closed by other m...
Definition: callbacks.c:1823
void callbacks_update_statusbar(void)
Displays additional information in the statusbar.
Definition: callbacks.c:3910
void callbacks_open_activate(GtkMenuItem *menuitem, gpointer user_data)
The file -> open action was selected.
Definition: callbacks.c:351
void callbacks_align_files_from_sel_clicked(GtkMenuItem *menu_item, gpointer user_data)
The edit -> align layers menu item was selected.
Definition: callbacks.c:3696
void callbacks_analyze_active_drill_activate(GtkMenuItem *menuitem, gpointer user_data)
The analyze -> analyze drill file menu item was selected.
Definition: callbacks.c:1514
static gint callbacks_get_selected_row_index(void)
This fcn returns the index of selected layer (selected in the layer window on left).
Definition: callbacks.c:2427
gerbv_image_t * merge_images(int type)
Go through each file and look at visibility, then type.
Definition: callbacks.c:439
void open_project(char *project_filename)
The file -> open menu item was selected.
Definition: callbacks.c:184
void callbacks_analyze_active_gerbers_activate(GtkMenuItem *menuitem, gpointer user_data)
The analyze -> analyze Gerbers menu item was selected.
Definition: callbacks.c:1145
gboolean callbacks_drawingarea_button_release_event(GtkWidget *widget, GdkEventButton *event)
Definition: callbacks.c:3772
void callbacks_about_activate(GtkMenuItem *menuitem, gpointer user_data)
The help -> about menu item was selected.
Definition: callbacks.c:1890
void callbacks_new_project_activate(GtkMenuItem *menuitem, gpointer user_data)
The file -> new menu item was selected.
Definition: callbacks.c:151
void callbacks_toggle_layer_visibility_activate(GtkMenuItem *menuitem, gpointer user_data)
View/"Toggle visibility layer X" or Current layer/"Toggle visibility" menu item was activated.
Definition: callbacks.c:1057
Header info for the GUI callback functions.
Header info for the GDK rendering functions.
Header info for the cairo rendering functions and the related selection calculating functions.
const char * drill_g_code_name(drill_g_code_t g_code)
Return drill G-code name by code number.
Definition: drill.c:2939
const char * drill_m_code_name(drill_m_code_t m_code)
Return drill M-code name by code number.
Definition: drill.c:3013
Header info for the Excellon drill parsing functions.
void gerbv_drill_stats_destroy(gerbv_drill_stats_t *stats)
Definition: drill_stats.c:101
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:42
gboolean gerbv_export_dxf_file_from_image(const gchar *file_name, gerbv_image_t *input_img, gerbv_user_transformation_t *trans)
Export an image to a new file in DXF format.
Definition: export-dxf.cpp:78
gboolean gerbv_export_geda_pcb_file_from_image(const gchar *file_name, gerbv_image_t *input_img, gerbv_user_transformation_t *trans)
Export an image to a new file in gEDA PCB format.
void gerbv_export_png_file_from_project(gerbv_project_t *gerbvProject, gerbv_render_info_t *renderInfo, gchar const *filename)
Render a project to a PNG file using user-specified render info.
Definition: export-image.c:229
void gerbv_export_postscript_file_from_project_autoscaled(gerbv_project_t *gerbvProject, gchar const *filename)
Render a project to a Postscript file, autoscaling the layers to fit inside the specified image dimen...
Definition: export-image.c:254
void gerbv_export_svg_file_from_project_autoscaled_with_options(gerbv_project_t *gerbvProject, gchar const *filename, gboolean exportLayersAsSvgLayers)
Render a project to a SVG file, optionally exporting visible layers as Inkscape layers.
Definition: export-image.c:276
void gerbv_export_png_file_from_project_autoscaled(gerbv_project_t *gerbvProject, int widthInPixels, int heightInPixels, gchar const *filename)
Render a project to a PNG file, autoscaling the layers to fit inside the specified image dimensions.
Definition: export-image.c:219
void gerbv_export_pdf_file_from_project_autoscaled(gerbv_project_t *gerbvProject, gchar const *filename)
Render a project to a PDF file, autoscaling the layers to fit inside the specified image dimensions.
Definition: export-image.c:241
gboolean gerbv_export_isel_drill_file_from_image(const gchar *filename, gerbv_image_t *inputImage, gerbv_user_transformation_t *transform)
Export an image to a new file in ISEL NCP drill format.
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:106
void gerbv_image_copy_image(gerbv_image_t *sourceImage, gerbv_user_transformation_t *transform, gerbv_image_t *destinationImage)
Copy an image into an existing image, effectively merging the two together.
Definition: gerb_image.c:989
void gerbv_image_delete_net(gerbv_net_t *currentNet)
Delete a net in an existing image.
Definition: gerb_image.c:1033
gerbv_image_t * gerbv_image_duplicate_image(gerbv_image_t *sourceImage, gerbv_user_transformation_t *transform)
Duplicate an existing image and return the new copy.
Definition: gerb_image.c:941
void gerbv_stats_destroy(gerbv_stats_t *stats)
Definition: gerb_stats.c:103
const char * gerber_d_code_name(int d_code)
Return Gerber D-code name by code number.
Definition: gerber.c:2833
const char * gerber_g_code_name(int g_code)
Return Gerber G-code name by code number.
Definition: gerber.c:2844
const char * gerber_m_code_name(int m_code)
Return Gerber M-code name by code number.
Definition: gerber.c:2870
const char * gerbv_interpolation_name(gerbv_interpolation_t interp)
Return string name of gerbv_interpolation_t interpolation.
Definition: gerbv.c:116
gerbv_fileinfo_t * gerbv_get_fileinfo_for_image(const gerbv_image_t *image, const gerbv_project_t *project)
Definition: gerbv.c:1132
void gerbv_open_layer_from_filename(gerbv_project_t *gerbvProject, gchar const *filename)
Open a file, parse the contents, and add a new layer to an existing project.
Definition: gerbv.c:243
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:783
int gerbv_transform_coord_for_image(double *x, double *y, const gerbv_image_t *image, const gerbv_project_t *project)
Definition: gerbv.c:1175
The main header file for the libgerbv library.
@ GERBV_APERTURE_STATE_OFF
Definition: gerbv.h:179
@ GERBV_APERTURE_STATE_ON
Definition: gerbv.h:180
@ GERBV_APERTURE_STATE_FLASH
Definition: gerbv.h:181
gerbv_render_types_t
Definition: gerbv.h:368
@ 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_message_type_t
Definition: gerbv.h:149
@ GERBV_MESSAGE_ERROR
Definition: gerbv.h:150
@ GERBV_MESSAGE_NOTE
Definition: gerbv.h:152
@ GERBV_MESSAGE_FATAL
Definition: gerbv.h:149
@ GERBV_MESSAGE_WARNING
Definition: gerbv.h:151
gerbv_aperture_type_t
Definition: gerbv.h:158
@ GERBV_APTYPE_MACRO_LINE20
Definition: gerbv.h:170
@ GERBV_APTYPE_MACRO_LINE21
Definition: gerbv.h:171
@ GERBV_APTYPE_OVAL
Definition: gerbv.h:162
@ GERBV_APTYPE_MACRO_OUTLINE
Definition: gerbv.h:166
@ GERBV_APTYPE_MACRO_CIRCLE
Definition: gerbv.h:165
@ GERBV_APTYPE_MACRO
Definition: gerbv.h:164
@ GERBV_APTYPE_CIRCLE
Definition: gerbv.h:160
@ GERBV_APTYPE_MACRO_POLYGON
Definition: gerbv.h:167
@ GERBV_APTYPE_RECTANGLE
Definition: gerbv.h:161
@ GERBV_APTYPE_MACRO_THERMAL
Definition: gerbv.h:169
@ GERBV_APTYPE_MACRO_LINE22
Definition: gerbv.h:172
@ GERBV_APTYPE_MACRO_MOIRE
Definition: gerbv.h:168
gerbv_interpolation_t
Definition: gerbv.h:303
@ GERBV_INTERPOLATION_LINEARx01
Definition: gerbv.h:305
@ GERBV_INTERPOLATION_PAREA_START
Definition: gerbv.h:309
@ GERBV_INTERPOLATION_LINEARx001
Definition: gerbv.h:306
@ GERBV_INTERPOLATION_CW_CIRCULAR
Definition: gerbv.h:307
@ GERBV_INTERPOLATION_PAREA_END
Definition: gerbv.h:310
@ GERBV_INTERPOLATION_LINEARx10
Definition: gerbv.h:304
@ GERBV_INTERPOLATION_CCW_CIRCULAR
Definition: gerbv.h:308
@ GERBV_INTERPOLATION_LINEARx1
Definition: gerbv.h:303
gerbv_layertype_t
Definition: gerbv.h:328
@ GERBV_LAYERTYPE_RS274X
Definition: gerbv.h:329
@ GERBV_LAYERTYPE_DRILL
Definition: gerbv.h:330
int interface_reopen_question(GSList *fns, GSList *fns_is_mod, GSList *fns_cnt, GSList *fns_lay_num)
This dialog box shows a text message with three buttons in the case if the file to be open was alread...
Definition: interface.c:2092
void interface_show_alert_dialog(gchar *primaryText, gchar *secondaryText, gboolean show_checkbox, gboolean *ask_to_show_again)
This dialog box shows a textmessage and one button: "OK".
Definition: interface.c:2222
gboolean interface_get_alert_dialog_response(const gchar *primaryText, const gchar *secondaryText, gboolean show_checkbox, gboolean *ask_to_show_again, const gchar *true_button_label, const gchar *false_button_label)
This dialog box shows a message and two buttons: "True" and "False".
Definition: interface.c:1874
Header info for the GUI building functions for Gerber Viewer.
gerbv_project_t * mainProject
Global state variable to keep track of what's happening on the screen.
Definition: main.c:201
Header info for common structs and functions used for the GUI application.
int project_is_gerbv_project(const char *filename, gboolean *ret)
Checks whether the supplied file look like a gerbv project by reading the first line and checking if ...
Definition: project.c:901
Header info for loading and saving project files.
void render_calculate_zoom_from_outline(GtkWidget *widget, GdkEventButton *event)
Will determine the outline of the zoomed regions.
Definition: render.c:144
gerbv_stats_t * generate_gerber_analysis(void)
Definition: render.c:655
void render_draw_measure_distance(void)
Displays a measured distance graphically on screen and in statusbar.
Definition: render.c:357
void render_toggle_measure_line(void)
Draws/erases measure line.
Definition: render.c:327
gerbv_drill_stats_t * generate_drill_analysis(void)
Definition: render.c:682
Header info for the rendering support functions for gerbv.
Header info for the selection support functions for libgerbv.
guint16 alpha
Definition: gerbv.h:750
gchar * fullPathname
Definition: gerbv.h:753
gerbv_image_t * image
Definition: gerbv.h:748
gerbv_user_transformation_t transform
Definition: gerbv.h:755
gchar * name
Definition: gerbv.h:754
GdkColor color
Definition: gerbv.h:749
gboolean layer_dirty
Definition: gerbv.h:756
gboolean isVisible
Definition: gerbv.h:751
gerbv_layertype_t layertype
Definition: gerbv.h:734
gerbv_aperture_t * aperture[APERTURE_MAX]
Definition: gerbv.h:735
gerbv_image_info_t * info
Definition: gerbv.h:740
gchar * name
Definition: gerbv.h:650
gerbv_layer_t * layer
Definition: gerbv.h:680
double stop_y
Definition: gerbv.h:672
GString * label
Definition: gerbv.h:679
gerbv_aperture_state_t aperture_state
Definition: gerbv.h:675
double stop_x
Definition: gerbv.h:671
double start_x
Definition: gerbv.h:669
struct gerbv_net * next
Definition: gerbv.h:678
double start_y
Definition: gerbv.h:670
gerbv_interpolation_t interpolation
Definition: gerbv.h:676
gerbv_cirseg_t * cirseg
Definition: gerbv.h:677
int aperture
Definition: gerbv.h:674
gboolean use_cairo_svg
Definition: gerbv.h:774
gerbv_fileinfo_t ** file
Definition: gerbv.h:764
gchar * project
Definition: gerbv.h:773
gboolean show_invisible_selection
Definition: gerbv.h:769
GdkColor background
Definition: gerbv.h:762
gboolean check_before_delete
Definition: gerbv.h:768
gchar * path
Definition: gerbv.h:770
int max_files
Definition: gerbv.h:763
int last_loaded
Definition: gerbv.h:766
gdouble lowerLeftY
Definition: gerbv.h:790
gboolean show_cross_on_drill_holes
Definition: gerbv.h:794
gdouble scaleFactorX
Definition: gerbv.h:787
gint displayHeight
Definition: gerbv.h:793
gdouble lowerLeftX
Definition: gerbv.h:789
gerbv_render_types_t renderType
Definition: gerbv.h:791
gdouble scaleFactorY
Definition: gerbv.h:788
Header info for GTK widgets table functions.