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, "G85", stat->G85, _(drill_g_code_name(85)));
1618  table_add_row(G_table, "G90", stat->G90, _(drill_g_code_name(90)));
1619  table_add_row(G_table, "G91", stat->G91, _(drill_g_code_name(91)));
1620  table_add_row(G_table, "G93", stat->G93, _(drill_g_code_name(93)));
1621  table_add_row(G_table, "", stat->G_unknown, _("unknown G-codes"));
1622 
1623  table_set_sortable(G_table);
1624  gtk_container_add(GTK_CONTAINER(G_report_window), G_table->widget);
1625 
1626  /* M codes on active layers */
1627  GtkWidget *M_report_window = gtk_scrolled_window_new(NULL, NULL);
1628  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(M_report_window),
1629  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1630 
1631  struct table *M_table =
1632  table_new_with_columns(3, _("Code"), G_TYPE_STRING,
1633  pgettext("table", "Count"), G_TYPE_UINT,
1634  _("Note"), G_TYPE_STRING);
1635  table_set_column_align(M_table, 0, 1.0);
1636  table_set_column_align(M_table, 1, 1.0);
1637  gtk_tree_view_set_headers_clickable(
1638  GTK_TREE_VIEW(M_table->widget), TRUE);
1639  table_add_row(M_table, "M00", stat->M00, _(drill_m_code_name(0)));
1640  table_add_row(M_table, "M01", stat->M01, _(drill_m_code_name(1)));
1641  table_add_row(M_table, "M18", stat->M18, _(drill_m_code_name(18)));
1642  table_add_row(M_table, "M25", stat->M25, _(drill_m_code_name(25)));
1643  table_add_row(M_table, "M30", stat->M30, _(drill_m_code_name(30)));
1644  table_add_row(M_table, "M45", stat->M45, _(drill_m_code_name(45)));
1645  table_add_row(M_table, "M47", stat->M47, _(drill_m_code_name(47)));
1646  table_add_row(M_table, "M48", stat->M48, _(drill_m_code_name(48)));
1647  table_add_row(M_table, "M71", stat->M71, _(drill_m_code_name(71)));
1648  table_add_row(M_table, "M72", stat->M72, _(drill_m_code_name(72)));
1649  table_add_row(M_table, "M95", stat->M95, _(drill_m_code_name(95)));
1650  table_add_row(M_table, "M97", stat->M97, _(drill_m_code_name(97)));
1651  table_add_row(M_table, "M98", stat->M98, _(drill_m_code_name(98)));
1652  table_add_row(M_table, "", stat->M_unknown, _("unknown M-codes"));
1653 
1654  table_set_sortable(M_table);
1655  gtk_container_add(GTK_CONTAINER(M_report_window), M_table->widget);
1656 
1657  /* Misc codes */
1658  GtkWidget *misc_report_window = gtk_scrolled_window_new(NULL, NULL);
1659  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(misc_report_window),
1660  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1661 
1662  struct table *misc_table =
1663  table_new_with_columns(2,
1664  /* Count is string for value hide. */
1665  pgettext("table", "Count"), G_TYPE_STRING,
1666  _("Code"), G_TYPE_STRING);
1667  table_set_column_align(misc_table, 0, 1.0);
1668  str = g_strdup_printf("%d", stat->comment);
1669  table_add_row(misc_table, str,_("Comments"));
1670  g_free(str);
1671  str = g_strdup_printf("%d", stat->unknown);
1672  table_add_row(misc_table, str, _("Unknown codes"));
1673  g_free(str);
1674  str = g_strdup_printf("%d", stat->R);
1675  table_add_row(misc_table, str, _("Repeat hole (R)"));
1676  g_free(str);
1677  if (stat->detect != NULL ) {
1678  table_add_row(misc_table, "", stat->detect);
1679  }
1680 
1681  table_set_sortable(misc_table);
1682  gtk_container_add(GTK_CONTAINER(misc_report_window),
1683  misc_table->widget);
1684 
1685  /* Drill usage on active layers */
1686  GtkWidget *drill_usage_report_window =
1687  gtk_scrolled_window_new(NULL, NULL);
1688  gtk_scrolled_window_set_policy(
1689  GTK_SCROLLED_WINDOW(drill_usage_report_window),
1690  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1691 
1692  struct table *drill_usage_table = table_new_with_columns(4,
1693  _("Drill no."), G_TYPE_UINT,
1694  _("Dia."), G_TYPE_DOUBLE,
1695  _("Units"), G_TYPE_STRING,
1696  pgettext("table", "Count"), G_TYPE_UINT);
1697 
1698  table_set_column_align(drill_usage_table, 0, 1.0);
1699  table_set_column_align(drill_usage_table, 3, 1.0);
1700  gtk_tree_view_set_headers_clickable(
1701  GTK_TREE_VIEW(drill_usage_table->widget), TRUE);
1702 
1704  for (drill_list = stat->drill_list;
1705  drill_list != NULL; drill_list = drill_list->next) {
1706  if (drill_list->drill_num == -1)
1707  break; /* No drill list */
1708 
1709  table_add_row(drill_usage_table,
1710  drill_list->drill_num,
1711  drill_list->drill_size,
1712  drill_list->drill_unit,
1713  drill_list->drill_count);
1714  }
1715 
1716  table_set_sortable(drill_usage_table);
1717  gtk_container_add(GTK_CONTAINER(drill_usage_report_window),
1718  drill_usage_table->widget);
1719 
1720  /* Create top level dialog window for report */
1721  GtkWidget *analyze_active_drill;
1722  analyze_active_drill = gtk_dialog_new_with_buttons(
1723  _("Drill codes report on visible layers"),
1724  NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
1725  GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
1726  gtk_container_set_border_width (GTK_CONTAINER (analyze_active_drill), 5);
1727 
1728  gtk_dialog_set_default_response (GTK_DIALOG(analyze_active_drill),
1729  GTK_RESPONSE_ACCEPT);
1730  g_signal_connect_after (G_OBJECT(analyze_active_drill),
1731  "response",
1732  G_CALLBACK (gtk_widget_destroy),
1733  GTK_WIDGET(analyze_active_drill));
1734 
1735  /* Put general report text into scrolled window */
1736  GtkWidget *general_report_window =
1737  gtk_scrolled_window_new(NULL, NULL);
1738  gtk_scrolled_window_set_policy(
1739  GTK_SCROLLED_WINDOW(general_report_window),
1740  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1741 
1742  GtkWidget *vbox = gtk_vbox_new(0, 0);
1743  gtk_box_pack_start(GTK_BOX(vbox), general_label, 0, 0, 0);
1744  gtk_box_pack_start(GTK_BOX(vbox), general_table->widget, 0, 0, 0);
1745  gtk_scrolled_window_add_with_viewport(
1746  GTK_SCROLLED_WINDOW(general_report_window), vbox);
1747 
1748  /* Create tabbed notebook widget and add report widgets. */
1749  GtkWidget *notebook = gtk_notebook_new();
1750 
1751  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1752  GTK_WIDGET(general_report_window),
1753  gtk_label_new(_("General")));
1754 
1755  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1756  GTK_WIDGET(G_report_window),
1757  gtk_label_new(_("G codes")));
1758 
1759  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1760  GTK_WIDGET(M_report_window),
1761  gtk_label_new(_("M codes")));
1762 
1763  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1764  GTK_WIDGET(misc_report_window),
1765  gtk_label_new(_("Misc. codes")));
1766 
1767  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1768  GTK_WIDGET(drill_usage_report_window),
1769  gtk_label_new(_("Drill usage")));
1770 
1771  /* Now put notebook into dialog window and show the whole thing */
1772  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(analyze_active_drill)->vbox),
1773  GTK_WIDGET(notebook));
1774 
1775  if (screen.settings) {
1776  analyze_window_size_restore(analyze_active_drill);
1777  g_signal_connect (G_OBJECT(analyze_active_drill), "response",
1778  G_CALLBACK (analyze_window_size_store),
1779  GTK_WIDGET(analyze_active_drill));
1780  } else {
1781  gtk_window_set_default_size(GTK_WINDOW(analyze_active_drill),
1782  640, 320);
1783  }
1784 
1785  gtk_widget_show_all(analyze_active_drill);
1786 
1788 }
1789 
1790 /* --------------------------------------------------------- */
1791 void
1792 callbacks_control_gerber_options_activate (GtkMenuItem *menuitem,
1793  gpointer user_data)
1794 {
1795 
1796 }
1797 
1798 /* --------------------------------------------------------- */
1799 void
1800 callbacks_online_manual_activate (GtkMenuItem *menuitem,
1801  gpointer user_data)
1802 {
1803 
1804 }
1805 
1806 /* --------------------------------------------------------- */
1813 gboolean
1814 callbacks_quit_activate (GtkMenuItem *menuitem,
1815  gpointer user_data)
1816 {
1817  gboolean layers_dirty = FALSE;
1818  gint idx;
1819 
1820  for (idx = 0; idx<=mainProject->last_loaded; idx++) {
1821  if (mainProject->file[idx] == NULL) break;
1822  layers_dirty = layers_dirty || mainProject->file[idx]->layer_dirty;
1823  }
1824 
1825  if (layers_dirty &&
1827  _("Do you want to close all open layers and quit the program?"),
1828  _("Quitting the program will cause any unsaved changes "
1829  "to be lost."),
1830  FALSE, NULL, GTK_STOCK_QUIT, GTK_STOCK_CANCEL)) {
1831  return TRUE; // stop propagation of the delete_event.
1832  // this would destroy the gui but not return from the gtk event loop.
1833  }
1834 
1835  /* Save background color */
1836  if (screen.settings && !screen.background_is_from_project) {
1837  guint clr;
1838  GdkColor *bg = &mainProject->background;
1839 
1840  clr = bg->red/257<<16 | bg->green/257<<8 | bg->blue/257;
1841  g_settings_set_uint (screen.settings, "background-color", clr);
1842  }
1843 
1844  /* Save main window size and postion */
1845  if (screen.settings) {
1846  GtkWindow *win = GTK_WINDOW(screen.win.topLevelWindow);
1847  gint32 xy[2];
1848  GVariant *var;
1849  gboolean is_max;
1850 
1851  is_max = FALSE != (GDK_WINDOW_STATE_MAXIMIZED & gdk_window_get_state (
1852  gtk_widget_get_window (GTK_WIDGET(win))));
1853  g_settings_set_boolean (screen.settings, "window-maximized", is_max);
1854 
1855  if (!is_max) {
1856  gtk_window_get_size (win, (gint *)xy, (gint *)(xy+1));
1857  var = g_variant_new_fixed_array (G_VARIANT_TYPE_INT32, xy, 2,
1858  sizeof (xy[0]));
1859  g_settings_set_value (screen.settings, "window-size", var);
1860 
1861  gtk_window_get_position (win, (gint *)xy, (gint *)(xy+1));
1862  var = g_variant_new_fixed_array (G_VARIANT_TYPE_INT32, xy, 2,
1863  sizeof (xy[0]));
1864  g_settings_set_value (screen.settings, "window-position", var);
1865  }
1866  }
1867 
1868  gerbv_unload_all_layers (mainProject);
1869  gtk_main_quit();
1870 
1871  return FALSE;
1872 }
1873 
1874 /* --------------------------------------------------------- */
1880 void
1881 callbacks_about_activate (GtkMenuItem *menuitem,
1882  gpointer user_data)
1883 {
1884  GtkWidget *aboutdialog1;
1885  /* TRANSLATORS: Replace this string with your names, one name per line. */
1886  gchar *translators = _("translator-credits");
1887 
1888  gchar *string = g_strdup_printf(_(
1889  "Gerbv — a Gerber (RS-274/X) viewer\n"
1890  "\n"
1891  "Version %s\n"
1892  "Compiled on %s at %s\n"
1893  "\n"
1894  "Gerbv was originally developed as part of the gEDA Project "
1895  "but is now separately maintained.\n"
1896  "\n"
1897  "For more information see:\n"
1898  " gerbv homepage: https://gerbv.github.io/\n"
1899  " gerbv repository: https://github.com/gerbv/gerbv"),
1900  VERSION, __DATE__, __TIME__);
1901 
1902 #if GTK_CHECK_VERSION(2,6,0)
1903  gchar *license = g_strdup_printf(_(
1904  "Gerbv — a Gerber (RS-274/X) viewer\n"
1905  "\n"
1906  "Copyright (C) 2000—2007 Stefan Petersen\n"
1907  "\n"
1908  "This program is free software: you can redistribute it and/or modify\n"
1909  "it under the terms of the GNU General Public License as published by\n"
1910  "the Free Software Foundation, either version 2 of the License, or\n"
1911  "(at your option) any later version.\n"
1912  "\n"
1913  "This program is distributed in the hope that it will be useful,\n"
1914  "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1915  "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1916  "GNU General Public License for more details.\n\n"
1917  "You should have received a copy of the GNU General Public License\n"
1918  "along with this program. If not, see <http://www.gnu.org/licenses/>."));
1919 
1920  #include "authors.c"
1921 
1922  int a_size, i;
1923  gchar **a;
1924 
1925  aboutdialog1 = gtk_about_dialog_new ();
1926  gtk_container_set_border_width (GTK_CONTAINER (aboutdialog1), 5);
1927  gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (aboutdialog1), VERSION);
1928  gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (aboutdialog1), _("Gerbv"));
1929 
1930  gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG (aboutdialog1), translators);
1931  gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (aboutdialog1), string);
1932  gtk_about_dialog_set_license(GTK_ABOUT_DIALOG (aboutdialog1), license);
1933 
1934  /* The authors.c file is autogenerated at build time */
1935  a_size = sizeof(authors_string_array)/sizeof(authors_string_array[0]);
1936  a = g_new(gchar *, a_size);
1937  for (i = 0; i < a_size; i++)
1938  a[i] = _(authors_string_array[i]);
1939 
1940  gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG (aboutdialog1), (const gchar **)a);
1941  gtk_about_dialog_set_website(GTK_ABOUT_DIALOG (aboutdialog1), "https://gerbv.github.io/");
1942  g_free(a);
1943 
1944  g_signal_connect (G_OBJECT(aboutdialog1),"response",
1945  G_CALLBACK (gtk_widget_destroy), GTK_WIDGET(aboutdialog1));
1946 
1947  g_free (string);
1948  g_free (license);
1949 #else
1950  aboutdialog1 = gtk_message_dialog_new ( GTK_WINDOW (screen.win.topLevelWindow),
1951  GTK_DIALOG_DESTROY_WITH_PARENT,
1952  GTK_MESSAGE_INFO,
1953  GTK_BUTTONS_CLOSE,
1954  string
1955  );
1956 
1957  gtk_window_set_title ( GTK_WINDOW (aboutdialog1), _("About Gerbv"));
1958 
1959  /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
1960  g_signal_connect_swapped (aboutdialog1, "response",
1961  G_CALLBACK (gtk_widget_destroy),
1962  aboutdialog1);
1963  g_free (string);
1964 #endif
1965 
1966  gtk_widget_show_all(GTK_WIDGET(aboutdialog1));
1967 
1968 }
1969 
1970 /* --------------------------------------------------------- */
1976 void
1977 callbacks_bugs_activate (GtkMenuItem *menuitem,
1978  gpointer user_data)
1979 {
1980  int i;
1981  #include "bugs.c"
1982 
1983  /* Create the top level dialog widget with an OK button */
1984  GtkWidget *bugs_dialog = gtk_dialog_new_with_buttons(_("Known bugs in Gerbv"),
1985  NULL,
1986  GTK_DIALOG_DESTROY_WITH_PARENT,
1987  GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1988  NULL);
1989  gtk_container_set_border_width (GTK_CONTAINER (bugs_dialog), 5);
1990  gtk_dialog_set_default_response (GTK_DIALOG(bugs_dialog),
1991  GTK_RESPONSE_ACCEPT);
1992  g_signal_connect (G_OBJECT(bugs_dialog), "response",
1993  G_CALLBACK (gtk_widget_destroy), GTK_WIDGET(bugs_dialog));
1994 
1995  /* First create single bugs_string from bugs_string_array */
1996  GString *bugs_string = g_string_new(NULL);
1997  for (i=0; bugs_string_array[i] != NULL; i++) {
1998  /* gettext("") will return info string */
1999  g_string_append_printf(bugs_string, "%s\n",
2000  (bugs_string_array[i][0] == '\0') ? "" : _(bugs_string_array[i]));
2001  }
2002 
2003  /* Create GtkLabel to hold text */
2004  GtkWidget *bugs_label = gtk_label_new (bugs_string->str);
2005  g_string_free(bugs_string, TRUE);
2006  gtk_misc_set_alignment(GTK_MISC(bugs_label), 0, 0);
2007  gtk_misc_set_padding(GTK_MISC(bugs_label), 7, 7);
2008 
2009  /* Put text into scrolled window */
2010  GtkWidget *bugs_window = gtk_scrolled_window_new (NULL, NULL);
2011  gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(bugs_window),
2012  GTK_WIDGET(bugs_label));
2013  gtk_widget_set_size_request(bugs_window, 600, 300);
2014  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(bugs_dialog)->vbox),
2015  GTK_WIDGET(bugs_window));
2016 
2017  gtk_widget_show_all(GTK_WIDGET(bugs_dialog));
2018  gtk_dialog_run(GTK_DIALOG(bugs_dialog));
2019 
2020 }
2021 
2022 /* --------------------------------------------------------- */
2023 gdouble callbacks_calculate_actual_distance (gdouble inputDimension) {
2024  return screen_units(inputDimension);
2025 }
2026 
2027 /* --------------------------------------------------------- */
2028 void callbacks_update_ruler_pointers (void) {
2029  double xPosition, yPosition;
2030  xPosition = screenRenderInfo.lowerLeftX + (screen.last_x / screenRenderInfo.scaleFactorX);
2031  yPosition = screenRenderInfo.lowerLeftY + ((screenRenderInfo.displayHeight - screen.last_y) / screenRenderInfo.scaleFactorY);
2032 
2033  if (!((screen.unit == GERBV_MILS) && ((screenRenderInfo.scaleFactorX < 80)||(screenRenderInfo.scaleFactorY < 80)))) {
2034  xPosition = callbacks_calculate_actual_distance (xPosition);
2035  yPosition = callbacks_calculate_actual_distance (yPosition);
2036  }
2037  g_object_set (G_OBJECT (screen.win.hRuler), "position", xPosition, NULL);
2038  g_object_set (G_OBJECT (screen.win.vRuler), "position", yPosition, NULL);
2039 }
2040 
2041 /* --------------------------------------------------------- */
2042 static void
2043 callbacks_render_type_changed () {
2044  static gboolean isChanging = FALSE;
2045  if (isChanging)
2046  return;
2047 
2048  isChanging = TRUE;
2049  gerbv_render_types_t type = screenRenderInfo.renderType;
2050  GtkCheckMenuItem *check_item = screen.win.menu_view_render_group[type];
2051  DPRINTF("%s(): type = %d, check_item = %p\n", __FUNCTION__, type, check_item);
2052  gtk_check_menu_item_set_active (check_item, TRUE);
2053  gtk_combo_box_set_active (screen.win.sidepaneRenderComboBox, type);
2054 
2055  render_refresh_rendered_image_on_screen();
2056  isChanging = FALSE;
2057 }
2058 
2059 /* --------------------------------------------------------- */
2060 static void
2061 callbacks_units_changed (gerbv_gui_unit_t unit)
2062 {
2063  static gboolean isChanging = FALSE;
2064 
2065  if (isChanging)
2066  return;
2067 
2068  isChanging = TRUE;
2069  screen.unit = unit;
2070 
2071  if (unit == GERBV_MILS || unit == GERBV_MMS || unit == GERBV_INS) {
2072  gtk_combo_box_set_active (
2073  GTK_COMBO_BOX (screen.win.statusUnitComboBox),
2074  unit);
2075  gtk_check_menu_item_set_active (
2076  screen.win.menu_view_unit_group[unit], TRUE);
2077  }
2078 
2079  callbacks_update_ruler_scales ();
2080  callbacks_update_statusbar_coordinates (screen.last_x, screen.last_y);
2081 
2082  if (screen.tool == MEASURE)
2083  callbacks_update_statusbar_measured_distance (
2084  screen.measure_last_x,
2085  screen.measure_last_y);
2086 
2087  isChanging = FALSE;
2088 }
2089 
2090 /* --------------------------------------------------------- */
2091 static void
2092 callbacks_update_ruler_scales (void) {
2093  double xStart, xEnd, yStart, yEnd;
2094 
2095  xStart = screenRenderInfo.lowerLeftX;
2096  yStart = screenRenderInfo.lowerLeftY;
2097  xEnd = screenRenderInfo.lowerLeftX + (screenRenderInfo.displayWidth / screenRenderInfo.scaleFactorX);
2098  yEnd = screenRenderInfo.lowerLeftY + (screenRenderInfo.displayHeight / screenRenderInfo.scaleFactorY);
2099  /* mils can get super crowded with large boards, but inches are too
2100  large for most boards. So, we leave mils in for now and just switch
2101  to inches if the scale factor gets too small */
2102  if (!((screen.unit == GERBV_MILS) && ((screenRenderInfo.scaleFactorX < 80)||(screenRenderInfo.scaleFactorY < 80)))) {
2103  xStart = callbacks_calculate_actual_distance (xStart);
2104  xEnd = callbacks_calculate_actual_distance (xEnd);
2105  yStart = callbacks_calculate_actual_distance (yStart);
2106  yEnd = callbacks_calculate_actual_distance (yEnd);
2107  }
2108  /* make sure the widgets actually exist before setting (in case this gets
2109  called before everything is realized */
2110  if (screen.win.hRuler)
2111  gtk_ruler_set_range (GTK_RULER (screen.win.hRuler), xStart, xEnd, 0, xEnd - xStart);
2112  /* reverse y min and max, since the ruler starts at the top */
2113  if (screen.win.vRuler)
2114  gtk_ruler_set_range (GTK_RULER (screen.win.vRuler), yEnd, yStart, 0, yEnd - yStart);
2115 }
2116 
2117 /* --------------------------------------------------------- */
2118 void callbacks_update_scrollbar_limits (void){
2119  gerbv_render_info_t tempRenderInfo = {0, 0, 0, 0,
2121  screenRenderInfo.displayWidth,
2122  screenRenderInfo.displayHeight};
2123 
2124  GtkAdjustment *hAdjust = (GtkAdjustment *)screen.win.hAdjustment;
2125  GtkAdjustment *vAdjust = (GtkAdjustment *)screen.win.vAdjustment;
2126  gerbv_render_zoom_to_fit_display (mainProject, &tempRenderInfo);
2127  hAdjust->lower = tempRenderInfo.lowerLeftX;
2128  hAdjust->page_increment = hAdjust->page_size;
2129  hAdjust->step_increment = hAdjust->page_size / 10.0;
2130  vAdjust->lower = tempRenderInfo.lowerLeftY;
2131  vAdjust->page_increment = vAdjust->page_size;
2132  vAdjust->step_increment = vAdjust->page_size / 10.0;
2133  hAdjust->upper = tempRenderInfo.lowerLeftX + (tempRenderInfo.displayWidth / tempRenderInfo.scaleFactorX);
2134  hAdjust->page_size = screenRenderInfo.displayWidth / screenRenderInfo.scaleFactorX;
2135  vAdjust->upper = tempRenderInfo.lowerLeftY + (tempRenderInfo.displayHeight / tempRenderInfo.scaleFactorY);
2136  vAdjust->page_size = screenRenderInfo.displayHeight / screenRenderInfo.scaleFactorY;
2137  callbacks_update_scrollbar_positions ();
2138 }
2139 
2140 /* --------------------------------------------------------- */
2141 void callbacks_update_scrollbar_positions (void){
2142  gdouble positionX,positionY;
2143 
2144  positionX = screenRenderInfo.lowerLeftX;
2145  if (positionX < ((GtkAdjustment *)screen.win.hAdjustment)->lower)
2146  positionX = ((GtkAdjustment *)screen.win.hAdjustment)->lower;
2147  if (positionX > (((GtkAdjustment *)screen.win.hAdjustment)->upper - ((GtkAdjustment *)screen.win.hAdjustment)->page_size))
2148  positionX = (((GtkAdjustment *)screen.win.hAdjustment)->upper - ((GtkAdjustment *)screen.win.hAdjustment)->page_size);
2149  gtk_adjustment_set_value ((GtkAdjustment *)screen.win.hAdjustment, positionX);
2150 
2151  positionY = ((GtkAdjustment *)screen.win.vAdjustment)->upper - screenRenderInfo.lowerLeftY -
2152  ((GtkAdjustment *)screen.win.vAdjustment)->page_size +
2153  ((GtkAdjustment *)screen.win.vAdjustment)->lower;
2154  if (positionY < ((GtkAdjustment *)screen.win.vAdjustment)->lower)
2155  positionY = ((GtkAdjustment *)screen.win.vAdjustment)->lower;
2156  if (positionY > (((GtkAdjustment *)screen.win.vAdjustment)->upper - ((GtkAdjustment *)screen.win.vAdjustment)->page_size))
2157  positionY = (((GtkAdjustment *)screen.win.vAdjustment)->upper - ((GtkAdjustment *)screen.win.vAdjustment)->page_size);
2158  gtk_adjustment_set_value ((GtkAdjustment *)screen.win.vAdjustment, positionY);
2159 }
2160 
2161 /* --------------------------------------------------------- */
2162 gboolean
2163 callbacks_scrollbar_button_released (GtkWidget *widget, GdkEventButton *event){
2164  screen.off_x = 0;
2165  screen.off_y = 0;
2166  screen.state = NORMAL;
2167  render_refresh_rendered_image_on_screen();
2168  return FALSE;
2169 }
2170 
2171 /* --------------------------------------------------------- */
2172 gboolean
2173 callbacks_scrollbar_button_pressed (GtkWidget *widget, GdkEventButton *event){
2174  //screen.last_x = ((GtkAdjustment *)screen.win.hAdjustment)->value;
2175  screen.state = SCROLLBAR;
2176  return FALSE;
2177 }
2178 
2179 /* --------------------------------------------------------- */
2180 void callbacks_hadjustment_value_changed (GtkAdjustment *adjustment, gpointer user_data){
2181  /* make sure we're actually using the scrollbar to make sure we don't reset
2182  lowerLeftX during a scrollbar redraw during something else */
2183  if (screen.state == SCROLLBAR) {
2184  screenRenderInfo.lowerLeftX = gtk_adjustment_get_value (adjustment);
2185  }
2186 }
2187 
2188 /* --------------------------------------------------------- */
2189 void callbacks_vadjustment_value_changed (GtkAdjustment *adjustment, gpointer user_data){
2190  /* make sure we're actually using the scrollbar to make sure we don't reset
2191  lowerLeftY during a scrollbar redraw during something else */
2192  if (screen.state == SCROLLBAR) {
2193  screenRenderInfo.lowerLeftY = adjustment->upper -
2194  (gtk_adjustment_get_value (adjustment) + adjustment->page_size) + adjustment->lower;
2195  }
2196 }
2197 
2198 /* --------------------------------------------------------- */
2199 static void
2200 callbacks_layer_tree_visibility_toggled (gint index)
2201 {
2202  mainProject->file[index]->isVisible =
2203  !mainProject->file[index]->isVisible;
2204 
2205  callbacks_update_layer_tree ();
2206  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2207  render_refresh_rendered_image_on_screen ();
2208  } else {
2209  render_recreate_composite_surface ();
2210  callbacks_force_expose_event_for_screen ();
2211  }
2212 }
2213 
2214 /* --------------------------------------------------------- */
2215 static gint
2216 callbacks_get_col_num_from_tree_view_col (GtkTreeViewColumn *col)
2217 {
2218  GList *cols;
2219  gint num;
2220 
2221  g_return_val_if_fail ( col != NULL, -1 );
2222  g_return_val_if_fail ( col->tree_view != NULL, -1 );
2223  cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(col->tree_view));
2224  num = g_list_index(cols, (gpointer) col);
2225  g_list_free(cols);
2226  return num;
2227 }
2228 
2229 /* --------------------------------------------------------- */
2230 void
2231 callbacks_add_layer_button_clicked (GtkButton *button, gpointer user_data)
2232 {
2233  callbacks_open_activate (NULL, NULL);
2234 }
2235 
2236 /* --------------------------------------------------------- */
2237 void
2238 callbacks_unselect_all_tool_buttons (void) {
2239 
2240 }
2241 
2242 void
2243 callbacks_switch_to_normal_tool_cursor (gint toolNumber)
2244 {
2245  GdkWindow *drawing_area_window = screen.drawing_area->window;
2246  GdkCursor *cursor;
2247 
2248  switch (toolNumber) {
2249  case POINTER:
2250  gdk_window_set_cursor(drawing_area_window, GERBV_DEF_CURSOR);
2251  break;
2252  case PAN:
2253  cursor = gdk_cursor_new(GDK_FLEUR);
2254  gdk_window_set_cursor(drawing_area_window, cursor);
2255  gdk_cursor_destroy(cursor);
2256  break;
2257  case ZOOM:
2258  cursor = gdk_cursor_new(GDK_SIZING);
2259  gdk_window_set_cursor(drawing_area_window, cursor);
2260  gdk_cursor_destroy(cursor);
2261  break;
2262  case MEASURE:
2263  cursor = gdk_cursor_new(GDK_CROSSHAIR);
2264  gdk_window_set_cursor(drawing_area_window, cursor);
2265  gdk_cursor_destroy(cursor);
2266  break;
2267  default:
2268  break;
2269  }
2270 }
2271 
2272 /* --------------------------------------------------------- */
2273 void
2274 callbacks_switch_to_correct_cursor (void)
2275 {
2276  GdkWindow *drawing_area_window = screen.drawing_area->window;
2277  GdkCursor *cursor;
2278 
2279  if (screen.state == IN_MOVE) {
2280  cursor = gdk_cursor_new(GDK_FLEUR);
2281  gdk_window_set_cursor(drawing_area_window, cursor);
2282  gdk_cursor_destroy(cursor);
2283  return;
2284  }
2285  else if (screen.state == IN_ZOOM_OUTLINE) {
2286  cursor = gdk_cursor_new(GDK_SIZING);
2287  gdk_window_set_cursor(drawing_area_window, cursor);
2288  gdk_cursor_destroy(cursor);
2289  return;
2290  }
2291  callbacks_switch_to_normal_tool_cursor (screen.tool);
2292 }
2293 
2294 /* --------------------------------------------------------- */
2295 void
2296 callbacks_change_tool (GtkButton *button, gpointer user_data) {
2297  gint toolNumber = GPOINTER_TO_INT (user_data);
2298 
2299  /* make sure se don't get caught in endless recursion here */
2300  if (screen.win.updatingTools)
2301  return;
2302  screen.win.updatingTools = TRUE;
2303  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPointer), FALSE);
2304  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPan), FALSE);
2305  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonZoom), FALSE);
2306  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonMeasure), FALSE);
2307  switch (toolNumber) {
2308  case POINTER:
2309  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPointer), TRUE);
2310  screen.tool = POINTER;
2311  screen.state = NORMAL;
2312  utf8_strncpy(screen.statusbar.diststr,
2313  _("Click to select objects in the active layer. "
2314  "Middle click and drag to pan."),
2315  MAX_DISTLEN);
2316  break;
2317  case PAN:
2318  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPan), TRUE);
2319  screen.tool = PAN;
2320  screen.state = NORMAL;
2321  utf8_strncpy(screen.statusbar.diststr,
2322  _("Click and drag to pan. Right click and drag to zoom."),
2323  MAX_DISTLEN);
2324  break;
2325  case ZOOM:
2326  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonZoom), TRUE);
2327  screen.tool = ZOOM;
2328  screen.state = NORMAL;
2329  utf8_strncpy(screen.statusbar.diststr,
2330  _("Click and drag to zoom in. Shift+click to zoom out."),
2331  MAX_DISTLEN);
2332  break;
2333 
2334  case MEASURE:
2335  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonMeasure), TRUE);
2336  screen.tool = MEASURE;
2337  screen.state = NORMAL;
2338  utf8_strncpy(screen.statusbar.diststr,
2339  _("Click and drag to measure a distance or select two apertures."),
2340  MAX_DISTLEN);
2341 
2342  /* To not show previous measure drag-line */
2343  screen.measure_start_x = 0;
2344  screen.measure_start_y = 0;
2345  screen.measure_stop_x = 0;
2346  screen.measure_stop_y = 0;
2347 
2348  /* If two items are selected, measure they distance */
2349  if (selection_length (&screen.selectionInfo) == 2) {
2350  gerbv_selection_item_t item[2];
2351  gerbv_net_t *net[2];
2352 
2353  item[0] = selection_get_item_by_index(
2354  &screen.selectionInfo, 0);
2355  item[1] = selection_get_item_by_index(
2356  &screen.selectionInfo, 1);
2357  net[0] = item[0].net;
2358  net[1] = item[1].net;
2359 
2360  if ((net[0]->aperture_state ==
2361  net[1]->aperture_state)
2362  && (net[0]->aperture_state ==
2364  screen.measure_start_x = net[0]->stop_x;
2365  screen.measure_start_y = net[0]->stop_y;
2367  &screen.measure_start_x,
2368  &screen.measure_start_y,
2369  item[0].image,
2370  mainProject);
2371 
2372  screen.measure_stop_x = net[1]->stop_x;
2373  screen.measure_stop_y = net[1]->stop_y;
2375  &screen.measure_stop_x,
2376  &screen.measure_stop_y,
2377  item[1].image,
2378  mainProject);
2379 
2381  }
2382  }
2383  break;
2384  default:
2385  break;
2386  }
2387 
2388  callbacks_switch_to_normal_tool_cursor (toolNumber);
2390  screen.win.updatingTools = FALSE;
2391  callbacks_force_expose_event_for_screen();
2392 }
2393 
2394 /* --------------------------------------------------------- */
2395 static void
2396 callbacks_select_layer_row (gint rowIndex)
2397 {
2398  GtkTreeSelection *selection;
2399  GtkTreeIter iter;
2400  GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2401  ((GtkTreeView *) screen.win.layerTree);
2402 
2403  selection = gtk_tree_view_get_selection((GtkTreeView *) screen.win.layerTree);
2404 
2405  if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store),
2406  &iter, NULL, rowIndex)) {
2407  gtk_tree_selection_select_iter (selection, &iter);
2408  }
2409 }
2410 
2411 /* --------------------------------------------------------- */
2417 static gint
2419 {
2420  GtkTreeSelection *selection;
2421  GtkTreeIter iter;
2422  GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2423  ((GtkTreeView *) screen.win.layerTree);
2424  gint index=-1,i=0;
2425 
2426  /* This will only work in single or browse selection mode! */
2427  selection = gtk_tree_view_get_selection((GtkTreeView *) screen.win.layerTree);
2428  if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
2429  while (gtk_tree_model_iter_nth_child ((GtkTreeModel *)list_store,
2430  &iter, NULL, i)){
2431  if (gtk_tree_selection_iter_is_selected (selection, &iter)) {
2432  return i;
2433  }
2434  i++;
2435  }
2436  }
2437  return index;
2438 }
2439 
2440 /* --------------------------------------------------------- */
2441 void
2442 callbacks_remove_layer_button_clicked (GtkButton *button, gpointer user_data)
2443 {
2444  gint index = callbacks_get_selected_row_index ();
2445 
2446  if ((index >= 0) && (index <= mainProject->last_loaded)) {
2447  render_remove_selected_objects_belonging_to_layer (
2448  &screen.selectionInfo,
2449  mainProject->file[index]->image);
2450  update_selected_object_message (FALSE);
2451 
2452  gerbv_unload_layer (mainProject, index);
2453  callbacks_update_layer_tree ();
2454 
2455  index = MAX(0, index - 1);
2456  callbacks_select_layer_row (index);
2457 
2458  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2459  render_refresh_rendered_image_on_screen ();
2460  } else {
2461  render_recreate_composite_surface ();
2462  callbacks_force_expose_event_for_screen ();
2463  }
2464  }
2465 }
2466 
2467 /* --------------------------------------------------------- */
2468 void
2469 callbacks_move_layer_down_menu_activate (GtkMenuItem *menuitem, gpointer user_data) {
2470  callbacks_move_layer_down_button_clicked(NULL, NULL);
2471  gtk_widget_grab_focus (screen.win.layerTree);
2472 }
2473 
2474 /* --------------------------------------------------------- */
2475 void
2476 callbacks_move_layer_down_button_clicked (GtkButton *button, gpointer user_data) {
2477  gint index=callbacks_get_selected_row_index();
2478  if (index < 0) {
2479  show_no_layers_warning ();
2480  return;
2481  }
2482 
2483  if (index < mainProject->last_loaded) {
2484  gerbv_change_layer_order (mainProject, index, index + 1);
2485  callbacks_update_layer_tree ();
2486  callbacks_select_layer_row (index + 1);
2487 
2488  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2489  render_refresh_rendered_image_on_screen ();
2490  }
2491  else {
2492  render_recreate_composite_surface ();
2493  callbacks_force_expose_event_for_screen ();
2494  }
2495  }
2496 }
2497 
2498 /* --------------------------------------------------------- */
2499 void
2500 callbacks_move_layer_up_menu_activate (GtkMenuItem *menuitem, gpointer user_data) {
2501  callbacks_move_layer_up_button_clicked (NULL, NULL);
2502  gtk_widget_grab_focus (screen.win.layerTree);
2503 }
2504 
2505 /* --------------------------------------------------------- */
2506 void
2507 callbacks_move_layer_up_button_clicked (GtkButton *button, gpointer user_data) {
2508  gint index=callbacks_get_selected_row_index();
2509  if (index < 0) {
2510  show_no_layers_warning ();
2511  return;
2512  }
2513  if (index > 0) {
2514  gerbv_change_layer_order (mainProject, index, index - 1);
2515  callbacks_update_layer_tree ();
2516  callbacks_select_layer_row (index - 1);
2517  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2518  render_refresh_rendered_image_on_screen();
2519  }
2520  else {
2521  render_recreate_composite_surface ();
2522  callbacks_force_expose_event_for_screen ();
2523  }
2524  }
2525 }
2526 
2527 /* --------------------------------------------------------- */
2528 void callbacks_layer_tree_row_inserted (GtkTreeModel *tree_model, GtkTreePath *path,
2529  GtkTreeIter *oIter, gpointer user_data) {
2530  gint *indices=NULL,oldPosition,newPosition;
2531 
2532  if ((!screen.win.treeIsUpdating)&&(path != NULL)) {
2533  indices = gtk_tree_path_get_indices (path);
2534  if (indices) {
2535  newPosition = indices[0];
2536  oldPosition = callbacks_get_selected_row_index ();
2537  /* compensate for the fact that the old row has already
2538  been removed */
2539  if (oldPosition < newPosition)
2540  newPosition--;
2541  else
2542  oldPosition--;
2543  gerbv_change_layer_order (mainProject, oldPosition, newPosition);
2544 
2545  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2546  render_refresh_rendered_image_on_screen();
2547  }
2548  else {
2549  render_recreate_composite_surface ();
2550  callbacks_force_expose_event_for_screen ();
2551  }
2552  /* select the new line */
2553  GtkTreeSelection *selection;
2554  GtkTreeIter iter;
2555  GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2556  ((GtkTreeView *) screen.win.layerTree);
2557 
2558  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(screen.win.layerTree));
2559  if (gtk_tree_model_get_iter ((GtkTreeModel *)list_store, &iter, path))
2560  gtk_tree_selection_select_iter (selection, &iter);
2561  }
2562  }
2563 }
2564 
2565 /* --------------------------------------------------------- */
2566 void
2567 callbacks_show_color_picker_dialog (gint index){
2568  screen.win.colorSelectionDialog = NULL;
2569  GtkColorSelectionDialog *cs= (GtkColorSelectionDialog *) gtk_color_selection_dialog_new (_("Select a color"));
2570  GtkColorSelection *colorsel = (GtkColorSelection *) cs->colorsel;
2571 
2572  screen.win.colorSelectionDialog = (GtkWidget *) cs;
2573  screen.win.colorSelectionIndex = index;
2574  if (index >= 0)
2575  gtk_color_selection_set_current_color (colorsel, &mainProject->file[index]->color);
2576  else
2577  gtk_color_selection_set_current_color (colorsel, &mainProject->background);
2578  if ((screenRenderInfo.renderType >= GERBV_RENDER_TYPE_CAIRO_NORMAL)&&(index >= 0)) {
2579  gtk_color_selection_set_has_opacity_control (colorsel, TRUE);
2580  gtk_color_selection_set_current_alpha (colorsel, mainProject->file[index]->alpha);
2581  }
2582  gtk_widget_show_all((GtkWidget *)cs);
2583  if (gtk_dialog_run ((GtkDialog*)cs) == GTK_RESPONSE_OK) {
2584  GtkColorSelection *colorsel = (GtkColorSelection *) cs->colorsel;
2585  gint rowIndex = screen.win.colorSelectionIndex;
2586 
2587  if (index >= 0) {
2588  gtk_color_selection_get_current_color (colorsel, &mainProject->file[rowIndex]->color);
2589  gdk_colormap_alloc_color(gdk_colormap_get_system(), &mainProject->file[rowIndex]->color, FALSE, TRUE);
2590  }
2591  else {
2592  gtk_color_selection_get_current_color (colorsel, &mainProject->background);
2593  gdk_colormap_alloc_color(gdk_colormap_get_system(), &mainProject->background, FALSE, TRUE);
2594  }
2595  if ((screenRenderInfo.renderType >= GERBV_RENDER_TYPE_CAIRO_NORMAL)&&(index >= 0)) {
2596  mainProject->file[rowIndex]->alpha = gtk_color_selection_get_current_alpha (colorsel);
2597  }
2598 
2599  callbacks_update_layer_tree ();
2600  render_refresh_rendered_image_on_screen();
2601  }
2602  gtk_widget_destroy ((GtkWidget *)cs);
2603  screen.win.colorSelectionDialog = NULL;
2604 }
2605 
2606 /* --------------------------------------------------------- */
2607 void
2608 callbacks_invert_layer_clicked (GtkButton *button, gpointer user_data) {
2609  gint index=callbacks_get_selected_row_index();
2610  if (index < 0) {
2611  show_no_layers_warning ();
2612  return;
2613  }
2615  render_refresh_rendered_image_on_screen ();
2616  callbacks_update_layer_tree ();
2617 }
2618 
2619 /* --------------------------------------------------------- */
2620 void
2621 callbacks_change_layer_color_clicked (GtkButton *button, gpointer user_data) {
2622  gint index=callbacks_get_selected_row_index();
2623  if (index < 0) {
2624  show_no_layers_warning ();
2625  return;
2626  }
2627  callbacks_show_color_picker_dialog (index);
2628 }
2629 
2630 void
2631 callbacks_change_background_color_clicked (GtkButton *button, gpointer user_data) {
2632  callbacks_show_color_picker_dialog (-1);
2633 }
2634 
2635 /* --------------------------------------------------------------------------- */
2636 void
2637 callbacks_reload_layer_clicked (GtkButton *button, gpointer user_data)
2638 {
2639  gint index = callbacks_get_selected_row_index ();
2640 
2641  if (index < 0) {
2642  show_no_layers_warning ();
2643  return;
2644  }
2645 
2646  render_remove_selected_objects_belonging_to_layer (
2647  &screen.selectionInfo, mainProject->file[index]->image);
2648  update_selected_object_message (FALSE);
2649 
2650  gerbv_revert_file (mainProject, index);
2651  render_refresh_rendered_image_on_screen ();
2652  callbacks_update_layer_tree();
2653 }
2654 
2655 void
2656 callbacks_change_layer_edit_clicked (GtkButton *button, gpointer userData)
2657 {
2658  gint index = callbacks_get_selected_row_index();
2659  gerbv_fileinfo_t **files = mainProject->file;
2660  gerbv_user_transformation_t **transforms;
2661  int i, j;
2662 
2663  if (index < 0) {
2664  show_no_layers_warning ();
2665  return;
2666  }
2667 
2668  /* last_loaded == 0 if only one file is loaded */
2669  transforms = g_new (gerbv_user_transformation_t *,
2671  2 /* layer + NULL */ +
2672  1 /* if selected layer is visible */);
2673 
2674  /* [0] is selected layer */
2675  transforms[0] = &mainProject->file[index]->transform;
2676 
2677  /* Get visible Gerber files transformations */
2678  j = 1; /* [0] is alerady used */
2679  for (i = 0; i <= mainProject->last_loaded; i++) {
2680  if (files[i] && files[i]->isVisible)
2681  transforms[j++] = &files[i]->transform;
2682  }
2683 
2684  /* Terminate array with NULL */
2685  transforms[j] = NULL;
2686 
2687  interface_show_layer_edit_dialog(transforms, screen.unit);
2688  g_free (transforms);
2689  render_refresh_rendered_image_on_screen ();
2690  callbacks_update_layer_tree ();
2691 }
2692 
2693 /* --------------------------------------------------------------------------- */
2694 void
2695 callbacks_change_layer_format_clicked (GtkButton *button, gpointer user_data)
2696 {
2697  gerbv_HID_Attribute *attr = NULL;
2698  int n = 0;
2699  int i;
2700  gerbv_HID_Attr_Val * results = NULL;
2701  gint index = callbacks_get_selected_row_index();
2702  gchar *type;
2703  gint rc;
2704  if (index < 0) {
2705  show_no_layers_warning ();
2706  return;
2707  }
2708  DPRINTF("%s(): index = %d\n", __FUNCTION__, index);
2709  attr = mainProject->file[index]->image->info->attr_list;
2710  n = mainProject->file[index]->image->info->n_attr;
2711  type = mainProject->file[index]->image->info->type;
2712  if (type == NULL)
2713  type = N_("Unknown type");
2714 
2715  if (attr == NULL || n == 0)
2716  {
2717  interface_show_alert_dialog(_("This file type does not currently have any editable features"),
2718  _("Format editing is currently only supported for Excellon drill file formats."),
2719  FALSE,
2720  NULL);
2721  return;
2722  }
2723 
2724  DPRINTF("%s(): n = %d, attr = %p\n", __FUNCTION__, n, attr);
2725  if (n > 0)
2726  {
2727  if (mainProject->file[index]->layer_dirty) {
2729  _("This layer has changed!"),
2730  _("Editing the file type will reload the layer, "
2731  "destroying your changes. Click OK to edit "
2732  "the file type and destroy your changes, "
2733  "or Cancel to leave."),
2734  TRUE, NULL, GTK_STOCK_OK, GTK_STOCK_CANCEL);
2735  if (rc == 0) return; /* Return if user hit Cancel */
2736  }
2737 
2738  results = (gerbv_HID_Attr_Val *) malloc (n * sizeof (gerbv_HID_Attr_Val));
2739  if (results == NULL)
2740  GERB_FATAL_ERROR("%s(): malloc failed", __FUNCTION__);
2741 
2742  /* non-zero means cancel was picked */
2743  if (attribute_interface_dialog (attr, n, results,
2744  _("Edit file format"),
2745  _(type)))
2746  {
2747  return;
2748  }
2749 
2750  }
2751 
2752  DPRINTF("%s(): reloading layer\n", __func__);
2753  gerbv_revert_file (mainProject, index);
2754 
2755  for (i = 0; i < n; i++)
2756  {
2757  if (results[i].str_value)
2758  free (results[i].str_value);
2759  }
2760 
2761  if (results)
2762  free (results);
2763  render_refresh_rendered_image_on_screen();
2764  callbacks_update_layer_tree();
2765 }
2766 
2767 /* --------------------------------------------------------------------------- */
2768 gboolean
2769 callbacks_file_drop_event(GtkWidget *widget, GdkDragContext *dc,
2770  gint x, gint y, GtkSelectionData *data,
2771  guint info, guint time, gpointer p)
2772 {
2773  gchar **uris, **uri;
2774  GSList *fns = NULL;
2775 
2776  uris = gtk_selection_data_get_uris(data);
2777  if (!uris)
2778  return FALSE;
2779 
2780  for (uri = uris; *uri; uri++) {
2781  const char *prefix_str =
2782 #ifdef WIN32
2783  "file:///";
2784 #else
2785  "file://";
2786 #endif
2787  if (g_strrstr(*uri, prefix_str) == *uri)
2788  fns = g_slist_append(fns, g_uri_unescape_string(
2789  *uri + strlen(prefix_str), NULL));
2790  }
2791 
2792  open_files(fns);
2793  g_slist_free_full(fns, g_free);
2794  g_strfreev(uris);
2795 
2796  return TRUE;
2797 }
2798 
2799 /* --------------------------------------------------------------------------- */
2800 gboolean
2801 callbacks_layer_tree_key_press (GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
2802  /* if space is pressed while a color picker icon is in focus,
2803  show the color picker dialog. */
2804 
2805  if(event->keyval == GDK_space){
2806  GtkTreeView *tree;
2807  GtkTreePath *path;
2808  GtkTreeViewColumn *col;
2809  gint *indices;
2810  gint idx;
2811 
2812  tree = (GtkTreeView *) screen.win.layerTree;
2813  gtk_tree_view_get_cursor (tree, &path, &col);
2814  if (path) {
2815  indices = gtk_tree_path_get_indices (path);
2816  if (indices) {
2817  idx = callbacks_get_col_num_from_tree_view_col (col);
2818  if ((idx == 1) && (indices[0] <= mainProject->last_loaded)){
2819  callbacks_show_color_picker_dialog (indices[0]);
2820  }
2821  }
2822  gtk_tree_path_free (path);
2823  }
2824  }
2825  /* by default propagate the key press */
2826  return FALSE;
2827 }
2828 
2829 /* --------------------------------------------------------------------------- */
2830 gboolean
2831 callbacks_layer_tree_button_press (GtkWidget *widget, GdkEventButton *event,
2832  gpointer user_data)
2833 {
2834  GtkTreePath *path;
2835  GtkTreeIter iter;
2836  GtkTreeViewColumn *col;
2837  gint x,y;
2838  gint *indices;
2839 
2840  GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model (
2841  (GtkTreeView *) screen.win.layerTree);
2842 
2843  if (event->button == 1) {
2844  if (gtk_tree_view_get_path_at_pos ((GtkTreeView *) widget,
2845  event->x, event->y, &path, &col, &x, &y)
2846  && gtk_tree_model_get_iter ((GtkTreeModel *)list_store,
2847  &iter, path)) {
2848  indices = gtk_tree_path_get_indices (path);
2849  if (indices && (indices[0] <= mainProject->last_loaded)) {
2850  switch (callbacks_get_col_num_from_tree_view_col (col)) {
2851  case 0:
2852  callbacks_select_layer_row (indices[0]);
2853  callbacks_layer_tree_visibility_toggled (indices[0]);
2854  return TRUE;
2855  case 1:
2856  callbacks_show_color_picker_dialog (indices[0]);
2857  /* don't propagate the signal, since drag and drop can
2858  sometimes activated during color selection */
2859  return TRUE;
2860  }
2861  }
2862  }
2863  }
2864  /* don't pop up the menu if we don't have any loaded files */
2865  else if ((event->button == 3)&&(mainProject->last_loaded >= 0)) {
2866  gtk_menu_popup (GTK_MENU (screen.win.layerTreePopupMenu),
2867  NULL, NULL, NULL, NULL,
2868  event->button, event->time);
2869  }
2870 
2871  /* always allow the click to propagate and make sure the line is activated */
2872  return FALSE;
2873 }
2874 
2875 /* --------------------------------------------------------------------------- */
2876 void
2877 callbacks_update_layer_tree (void)
2878 {
2879  GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2880  ((GtkTreeView *) screen.win.layerTree);
2881  gint idx;
2882  GtkTreeIter iter;
2883  GtkTreeSelection *selection;
2884  gint oldSelectedRow;
2885 
2886  if (screen.win.treeIsUpdating)
2887  return;
2888 
2889  screen.win.treeIsUpdating = TRUE;
2890 
2891  oldSelectedRow = callbacks_get_selected_row_index();
2892  if (oldSelectedRow < 0)
2893  oldSelectedRow = 0;
2894 
2895  gtk_list_store_clear (list_store);
2896 
2897  for (idx = 0; idx <= mainProject->last_loaded; idx++) {
2898  GdkPixbuf *pixbuf, *blackPixbuf;
2899  unsigned char red, green, blue, alpha;
2900  guint32 color;
2901  gchar *layerName;
2902  gerbv_fileinfo_t *file;
2903 
2904  file = mainProject->file[idx];
2905  if (!file)
2906  continue;
2907 
2908  red = (unsigned char) (file->color.red * 255 / G_MAXUINT16);
2909  green = (unsigned char) (file->color.green * 255 / G_MAXUINT16);
2910  blue = (unsigned char) (file->color.blue *255 / G_MAXUINT16);
2911  alpha = (unsigned char) (file->alpha * 255 / G_MAXUINT16);
2912 
2913  color = red*(256*256*256) + green*(256*256) + blue*256 + alpha;
2914  pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 20, 15);
2915  gdk_pixbuf_fill (pixbuf, color);
2916 
2917  blackPixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 20, 15);
2918  color = 100*(256*256*256) + 100*(256*256) + 100*256 + 150;
2919  gdk_pixbuf_fill (blackPixbuf, color);
2920 
2921  /* copy the color area into the black pixbuf */
2922  gdk_pixbuf_copy_area (pixbuf, 1, 1, 18, 13, blackPixbuf, 1, 1);
2923  g_object_unref(pixbuf);
2924 
2925  gtk_list_store_append (list_store, &iter);
2926 
2927  gchar startChar[2],*modifiedCode;
2928  /* terminate the letter string */
2929  startChar[1] = 0;
2930 
2931  gint numberOfModifications = 0;
2932  if (file->transform.inverted) {
2933  startChar[0] = 'I';
2934  numberOfModifications++;
2935  }
2936  if (file->transform.mirrorAroundX
2937  || file->transform.mirrorAroundY) {
2938  startChar[0] = 'M';
2939  numberOfModifications++;
2940  }
2941  if (fabs(file->transform.translateX)
2942  > GERBV_PRECISION_LINEAR_INCH
2943  || fabs(file->transform.translateY)
2944  > GERBV_PRECISION_LINEAR_INCH) {
2945  startChar[0] = 'T';
2946  numberOfModifications++;
2947  }
2948  if (fabs(file->transform.scaleX - 1)
2949  > GERBV_PRECISION_LINEAR_INCH
2950  || fabs(file->transform.scaleY - 1)
2951  > GERBV_PRECISION_LINEAR_INCH) {
2952  startChar[0] = 'S';
2953  numberOfModifications++;
2954  }
2955  if (fabs(file->transform.rotation)
2956  > GERBV_PRECISION_ANGLE_RAD) {
2957  startChar[0] = 'R';
2958  numberOfModifications++;
2959  }
2960  if (numberOfModifications > 1)
2961  startChar[0] = '*';
2962  if (numberOfModifications == 0)
2963  modifiedCode = g_strdup ("");
2964  else
2965  modifiedCode = g_strdup (startChar);
2966 
2967  /* Display any unsaved layers differently to show the user they
2968  * are unsaved */
2969  if (file->layer_dirty == TRUE) {
2970  /* The layer has unsaved changes in it. Show layer name
2971  * in italics. */
2972  layerName = g_strconcat ("*", "<i>", file->name,
2973  "</i>", NULL);
2974  } else {
2975  /* Layer is clean. Show layer name using normal font. */
2976  layerName = g_strdup (file->name);
2977  }
2978 
2979  gtk_list_store_set (list_store, &iter,
2980  0, file->isVisible,
2981  1, blackPixbuf,
2982  2, layerName,
2983  3, modifiedCode,
2984  -1);
2985  g_free (layerName);
2986  g_free (modifiedCode);
2987  /* pixbuf has a refcount of 2 now, as the list store has added its own reference */
2988  g_object_unref(blackPixbuf);
2989  }
2990 
2991  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(screen.win.layerTree));
2992 
2993  /* if no line is selected yet, select the first row (if it has data) */
2994  /* or, select the line that was previously selected */
2995 
2996  if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
2997  if (gtk_tree_model_iter_nth_child ((GtkTreeModel *) list_store,
2998  &iter, NULL, oldSelectedRow)) {
2999  gtk_tree_selection_select_iter (selection, &iter);
3000  }
3001  }
3002  gboolean showItems = (mainProject->last_loaded >= 0);
3003  gtk_widget_set_sensitive (screen.win.curLayerMenuItem, showItems);
3004  gtk_widget_set_sensitive (screen.win.curAnalyzeMenuItem, showItems);
3005  gtk_widget_set_sensitive (screen.win.curEditMenuItem, showItems);
3006  for (unsigned int i = 0;
3007  i < G_N_ELEMENTS(screen.win.curFileMenuItem); i++) {
3008  gtk_widget_set_sensitive (screen.win.curFileMenuItem[i], showItems);
3009  }
3010  screen.win.treeIsUpdating = FALSE;
3011 }
3012 
3013 /* --------------------------------------------------------------------------- */
3014 void
3015 callbacks_display_object_properties_clicked (GtkButton *button, gpointer user_data)
3016 {
3017  gint index = callbacks_get_selected_row_index ();
3018  guint i;
3019 
3020  if (index < 0 || selection_length (&screen.selectionInfo) == 0) {
3021  interface_show_alert_dialog(_("No object is currently selected"),
3022  _("Objects must be selected using the pointer tool "
3023  "before you can view the object properties."),
3024  FALSE, NULL);
3025  return;
3026  }
3027 
3028  for (i = 0; i < selection_length (&screen.selectionInfo); i++){
3029  gerbv_selection_item_t sItem =
3030  selection_get_item_by_index (&screen.selectionInfo, i);
3031 
3032  gerbv_net_t *net = sItem.net;
3033  gerbv_image_t *image = sItem.image;
3034 
3036  /* Spacing for a pretty display */
3037  if (i != 0)
3038  g_message (" ");
3039 
3040  g_message (_("Object type: Polygon"));
3041  parea_report (net, image, mainProject);
3042  net_layer_file_report (net, image, mainProject);
3043  } else {
3044  switch (net->aperture_state) {
3045 
3048  /* Spacing for a pretty display */
3049  if (i != 0)
3050  g_message (" ");
3051  break;
3052 
3053  default:
3054  break;
3055  }
3056 
3057  aperture_state_report (net, image, mainProject);
3058  }
3059  }
3060  /* Use separator for different report requests */
3061  g_message ("---------------------------------------");
3062 }
3063 
3064 void
3065 callbacks_support_benchmark (gerbv_render_info_t *renderInfo) {
3066  int i;
3067  time_t start, now;
3068  GdkPixmap *renderedPixmap = gdk_pixmap_new (NULL, renderInfo->displayWidth,
3069  renderInfo->displayHeight, 24);
3070 
3071  // start by running the GDK (fast) rendering test
3072  i = 0;
3073  start = time(NULL);
3074  now = start;
3075  while( now - 30 < start) {
3076  i++;
3077  DPRINTF("Benchmark(): Starting redraw #%d\n", i);
3078  gerbv_render_to_pixmap_using_gdk (mainProject, renderedPixmap, renderInfo, NULL, NULL);
3079  now = time(NULL);
3080  DPRINTF("Elapsed time = %ld seconds\n", (long int) (now - start));
3081  }
3082  g_message(_("FAST (=GDK) mode benchmark: %d redraws "
3083  "in %ld seconds (%g redraws/second)"),
3084  i, (long int) (now - start), (double) i / (double)(now - start));
3085  gdk_pixmap_unref(renderedPixmap);
3086 
3087  // run the cairo (normal) render mode
3088  i = 0;
3089  start = time(NULL);
3090  now = start;
3092  while( now - 30 < start) {
3093  i++;
3094  DPRINTF("Benchmark(): Starting redraw #%d\n", i);
3095  cairo_surface_t *cSurface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
3096  renderInfo->displayWidth, renderInfo->displayHeight);
3097  cairo_t *cairoTarget = cairo_create (cSurface);
3098  gerbv_render_all_layers_to_cairo_target (mainProject, cairoTarget, renderInfo);
3099  cairo_destroy (cairoTarget);
3100  cairo_surface_destroy (cSurface);
3101  now = time(NULL);
3102  DPRINTF("Elapsed time = %ld seconds\n", (long int) (now - start));
3103  }
3104  g_message(_("NORMAL (=Cairo) mode benchmark: %d redraws "
3105  "in %ld seconds (%g redraws/second)"),
3106  i, (long int) (now - start), (double) i / (double)(now - start));
3107 }
3108 
3109 /* --------------------------------------------------------------------------- */
3110 void
3111 callbacks_benchmark_clicked (GtkButton *button, gpointer user_data)
3112 {
3113  // prepare render size and options (canvas size width and height are last 2 variables)
3114  gerbv_render_info_t renderInfo = {1.0, 1.0, 0, 0,
3115  GERBV_RENDER_TYPE_GDK, 640, 480};
3116 
3117  if (!interface_get_alert_dialog_response(_("Performance benchmark"),
3118  _("Application will be unresponsive for 1 minute! "
3119  "Run performance benchmark?"),
3120  FALSE, NULL, GTK_STOCK_OK, GTK_STOCK_CANCEL))
3121  return;
3122 
3123  GERB_COMPILE_WARNING(_("Running full zoom benchmark..."));
3124  while (g_main_context_iteration(NULL, FALSE)) {} // update log widget
3125 
3126  // autoscale the image for now...maybe we don't want to do this in order to
3127  // allow benchmarking of different zoom levels?
3129  callbacks_support_benchmark (&renderInfo);
3130 
3131  GERB_COMPILE_WARNING(_("Running x5 zoom benchmark..."));
3132  while (g_main_context_iteration(NULL, FALSE)) {} // update log widget
3133 
3134  renderInfo.lowerLeftX += (screenRenderInfo.displayWidth /
3135  screenRenderInfo.scaleFactorX) / 3.0;
3136  renderInfo.lowerLeftY += (screenRenderInfo.displayHeight /
3137  screenRenderInfo.scaleFactorY) / 3.0;
3138  renderInfo.scaleFactorX *= 5;
3139  renderInfo.scaleFactorY *= 5;
3140  callbacks_support_benchmark (&renderInfo);
3141 }
3142 
3143 /* --------------------------------------------------------------------------- */
3144 void
3145 callbacks_edit_object_properties_clicked (GtkButton *button, gpointer user_data){
3146 }
3147 /* --------------------------------------------------------------------------- */
3148 void
3149 callbacks_live_edit (GtkWidget *button, gpointer user_data){
3150  GtkDialog *toplevel = GTK_DIALOG(gtk_widget_get_toplevel (button));
3151  gtk_dialog_response(toplevel, GTK_RESPONSE_APPLY);
3152 }
3153 /* --------------------------------------------------------------------------- */
3154 void
3155 callbacks_move_objects_clicked (GtkButton *button, gpointer user_data){
3156  /* for testing, just hard code in some translations here */
3157  gerbv_image_move_selected_objects (screen.selectionInfo.selectedNodeArray, -0.050, 0.050);
3158  callbacks_update_layer_tree();
3159  selection_clear (&screen.selectionInfo);
3160  update_selected_object_message (FALSE);
3161  render_refresh_rendered_image_on_screen ();
3162 }
3163 
3164 /* --------------------------------------------------------------------------- */
3165 void
3166 callbacks_reduce_object_area_clicked (GtkButton *button, gpointer user_data){
3167  /* for testing, just hard code in some parameters */
3168  gerbv_image_reduce_area_of_selected_objects (screen.selectionInfo.selectedNodeArray, 0.20, 3, 3, 0.01);
3169  selection_clear (&screen.selectionInfo);
3170  update_selected_object_message (FALSE);
3171  render_refresh_rendered_image_on_screen ();
3172 }
3173 
3174 /* --------------------------------------------------------------------------- */
3175 void
3176 callbacks_delete_objects_clicked (GtkButton *button, gpointer user_data)
3177 {
3178  if (selection_length (&screen.selectionInfo) == 0) {
3180  _("No object is currently selected"),
3181  _("Objects must be selected using the pointer tool "
3182  "before they can be deleted."),
3183  FALSE,
3184  NULL);
3185  return;
3186  }
3187 
3188  gint index = callbacks_get_selected_row_index ();
3189  if (index < 0)
3190  return;
3191 
3194  _("Do you want to permanently delete "
3195  "the selected objects from <i>visible</i> layers?"),
3196  _("Gerbv currently has no undo function, so "
3197  "this action cannot be undone. This action "
3198  "will not change the saved file unless you "
3199  "save the file afterwards."),
3200  TRUE, &(mainProject->check_before_delete),
3201  GTK_STOCK_DELETE, GTK_STOCK_CANCEL)) {
3202  return;
3203  }
3204  }
3205 
3206  guint i;
3207  for (i = 0; i < selection_length (&screen.selectionInfo);) {
3208  gerbv_selection_item_t sel_item =
3209  selection_get_item_by_index (&screen.selectionInfo, i);
3210  gerbv_fileinfo_t *file_info =
3211  gerbv_get_fileinfo_for_image(sel_item.image, mainProject);
3212 
3213  /* Preserve currently invisible selection from deletion */
3214  if (!file_info->isVisible) {
3215  i++;
3216  continue;
3217  }
3218 
3219  file_info->layer_dirty = TRUE;
3220  selection_clear_item_by_index (&screen.selectionInfo, i);
3221  gerbv_image_delete_net (sel_item.net);
3222  }
3223  update_selected_object_message (FALSE);
3224 
3225  render_refresh_rendered_image_on_screen ();
3226  callbacks_update_layer_tree();
3227 }
3228 
3229 /* --------------------------------------------------------------------------- */
3230 gboolean
3231 callbacks_drawingarea_configure_event (GtkWidget *widget, GdkEventConfigure *event)
3232 {
3233  GdkDrawable *drawable = widget->window;
3234 
3235  gdk_drawable_get_size (drawable, &screenRenderInfo.displayWidth, &screenRenderInfo.displayHeight);
3236 
3237  /* set this up if cairo is compiled, since we may need to switch over to
3238  using the surface at any time */
3239  int x_off=0, y_off=0;
3240 
3241  if (GDK_IS_WINDOW(widget->window)) {
3242  /* query the window's backbuffer if it has one */
3243  GdkWindow *window = GDK_WINDOW(widget->window);
3244  gdk_window_get_internal_paint_info (window, &drawable, &x_off, &y_off);
3245  }
3246  if (screen.windowSurface)
3247  cairo_surface_destroy ((cairo_surface_t *)
3248  screen.windowSurface);
3249 
3250 #if defined(WIN32) || defined(QUARTZ)
3251  cairo_t *cairoTarget = gdk_cairo_create (GDK_WINDOW(widget->window));
3252 
3253  screen.windowSurface = cairo_get_target (cairoTarget);
3254  /* increase surface reference by one so it isn't freed when the cairo_t
3255  is destroyed next */
3256  screen.windowSurface = cairo_surface_reference (screen.windowSurface);
3257  cairo_destroy (cairoTarget);
3258 #else
3259  GdkVisual *visual = gdk_drawable_get_visual (drawable);
3260  screen.windowSurface = (gpointer) cairo_xlib_surface_create (GDK_DRAWABLE_XDISPLAY (drawable),
3261  GDK_DRAWABLE_XID (drawable),
3262  GDK_VISUAL_XVISUAL (visual),
3263  screenRenderInfo.displayWidth,
3264  screenRenderInfo.displayHeight);
3265 #endif
3266  /* if this is the first time, go ahead and call autoscale even if we don't
3267  have a model loaded */
3268  if ((screenRenderInfo.scaleFactorX < 0.001)||(screenRenderInfo.scaleFactorY < 0.001)) {
3269  gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
3270  }
3271  render_refresh_rendered_image_on_screen();
3272  return TRUE;
3273 }
3274 
3275 /* --------------------------------------------------------- */
3276 gboolean
3277 callbacks_drawingarea_expose_event (GtkWidget *widget, GdkEventExpose *event)
3278 {
3279  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
3280  GdkPixmap *new_pixmap;
3281  GdkGC *gc = gdk_gc_new(widget->window);
3282 
3283  /*
3284  * Create a pixmap with default background
3285  */
3286  new_pixmap = gdk_pixmap_new(widget->window,
3287  widget->allocation.width,
3288  widget->allocation.height,
3289  -1);
3290 
3291  gdk_gc_set_foreground(gc, &mainProject->background);
3292 
3293  gdk_draw_rectangle(new_pixmap, gc, TRUE,
3294  event->area.x, event->area.y,
3295  event->area.width, event->area.height);
3296 
3297  /*
3298  * Copy gerber pixmap onto background if we have one to copy.
3299  * Do translation at the same time.
3300  */
3301  if (screen.pixmap != NULL) {
3302  gdk_draw_pixmap(new_pixmap,
3303  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
3304  screen.pixmap,
3305  event->area.x - screen.off_x,
3306  event->area.y - screen.off_y,
3307  event->area.x, event->area.y,
3308  event->area.width, event->area.height);
3309  }
3310 
3311  /*
3312  * Draw the whole thing onto screen
3313  */
3314  gdk_draw_pixmap(widget->window,
3315  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
3316  new_pixmap,
3317  event->area.x, event->area.y,
3318  event->area.x, event->area.y,
3319  event->area.width, event->area.height);
3320 
3321  gdk_pixmap_unref(new_pixmap);
3322  gdk_gc_unref(gc);
3323 
3324  /*
3325  * Draw Zooming outline if we are in that mode
3326  */
3327  if (screen.state == IN_ZOOM_OUTLINE) {
3328  render_draw_zoom_outline(screen.centered_outline_zoom);
3329  }
3330  else if (screen.state == IN_MEASURE) {
3332  }
3333  if (screen.tool == MEASURE && screen.state != IN_MEASURE) {
3335  }
3336 
3337  return FALSE;
3338  }
3339 
3340  cairo_t *cr;
3341  int width, height;
3342  int x_off=0, y_off=0;
3343  GdkDrawable *drawable = widget->window;
3344 
3345  if (GDK_IS_WINDOW(widget->window)) {
3346  /* query the window's backbuffer if it has one */
3347  GdkWindow *window = GDK_WINDOW(widget->window);
3348  gdk_window_get_internal_paint_info (window,
3349  &drawable, &x_off, &y_off);
3350  }
3351  gdk_drawable_get_size (drawable, &width, &height);
3352 
3353 #if defined(WIN32) || defined(QUARTZ)
3354  /* FIXME */
3355  cr = gdk_cairo_create (GDK_WINDOW(widget->window));
3356 #else
3357  cairo_surface_t *buffert;
3358 
3359  GdkVisual *visual = gdk_drawable_get_visual (drawable);
3360  buffert = (gpointer) cairo_xlib_surface_create (GDK_DRAWABLE_XDISPLAY (drawable),
3361  GDK_DRAWABLE_XID (drawable),
3362  GDK_VISUAL_XVISUAL (visual),
3363  event->area.width, event->area.height);
3364  cr = cairo_create (buffert);
3365 #endif
3366  cairo_translate (cr, -event->area.x + screen.off_x, -event->area.y + screen.off_y);
3367  render_project_to_cairo_target (cr);
3368  cairo_destroy (cr);
3369 #if !defined(WIN32) && !defined(QUARTZ)
3370  cairo_surface_destroy (buffert);
3371 #endif
3372 
3373  if (screen.tool == MEASURE)
3375  return FALSE;
3376 }
3377 
3378 /* Transforms screen coordinates to board ones */
3379 static void
3380 callbacks_screen2board(gdouble *X, gdouble *Y, gint x, gint y) {
3381 
3382  /* make sure we don't divide by zero (which is possible if the gui
3383  isn't displayed yet */
3384  if ((screenRenderInfo.scaleFactorX > 0.001)||(screenRenderInfo.scaleFactorY > 0.001)) {
3385  *X = screenRenderInfo.lowerLeftX + (x / screenRenderInfo.scaleFactorX);
3386  *Y = screenRenderInfo.lowerLeftY + ((screenRenderInfo.displayHeight - y)
3387  / screenRenderInfo.scaleFactorY);
3388  }
3389  else {
3390  *X = *Y = 0.0;
3391  }
3392 }
3393 
3394 const char *gerbv_coords_pattern_mils_str = N_("%8.2f %8.2f");
3395 
3396 /* --------------------------------------------------------- */
3397 static void
3398 callbacks_update_statusbar_coordinates (gint x, gint y)
3399 {
3400  gdouble X, Y;
3401 
3402  callbacks_screen2board (&X, &Y, x, y);
3403 
3404  switch (screen.unit) {
3405  case GERBV_MILS:
3406  utf8_snprintf (screen.statusbar.coordstr, MAX_COORDLEN,
3407  _(gerbv_coords_pattern_mils_str),
3408  COORD2MILS (X), COORD2MILS (Y));
3409  break;
3410  case GERBV_MMS:
3411  utf8_snprintf (screen.statusbar.coordstr, MAX_COORDLEN,
3412  _("%8.3f %8.3f"),
3413  COORD2MMS (X), COORD2MMS (Y));
3414  break;
3415  default:
3416  utf8_snprintf (screen.statusbar.coordstr, MAX_COORDLEN,
3417  _("%4.5f %4.5f"),
3418  COORD2INS (X), COORD2INS (Y));
3419  }
3420 
3422 }
3423 
3424 static void
3425 update_selected_object_message (gboolean userTriedToSelect)
3426 {
3427  if (screen.tool != POINTER)
3428  return;
3429 
3430  gint selectionLength = selection_length (&screen.selectionInfo);
3431 
3432  if (selectionLength == 0) {
3433  if (userTriedToSelect) {
3434  /* Update status bar message to make sure the user
3435  * knows about needing to select the layer */
3436  gchar *str = g_new(gchar, MAX_DISTLEN);
3437  utf8_strncpy(str,
3438  _("No object selected. Objects can "
3439  "only be selected in the active "
3440  "layer."),
3441  MAX_DISTLEN - 7);
3442  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3443  "<b>%s</b>", str);
3444  g_free(str);
3445  } else {
3446  utf8_strncpy(screen.statusbar.diststr,
3447  _("Click to select objects in the "
3448  "active layer. Middle click and drag "
3449  "to pan."),
3450  MAX_DISTLEN);
3451  }
3452  } else {
3453  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3454  ngettext("%d object are currently selected",
3455  "%d objects are currently selected",
3456  selectionLength), selectionLength);
3457  }
3458 
3460 }
3461 
3462 /* --------------------------------------------------------- */
3463 gboolean
3464 callbacks_drawingarea_motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
3465 {
3466  int x, y;
3467  GdkModifierType state;
3468 
3469  if (event->is_hint)
3470  gdk_window_get_pointer (event->window, &x, &y, &state);
3471  else {
3472  x = event->x;
3473  y = event->y;
3474  state = event->state;
3475  }
3476 
3477  switch (screen.state) {
3478  case IN_MOVE: {
3479  if (screen.last_x != 0 || screen.last_y != 0) {
3480  /* Move pixmap to get a snappier feel of movement */
3481  screen.off_x += x - screen.last_x;
3482  screen.off_y += y - screen.last_y;
3483  }
3484  screenRenderInfo.lowerLeftX -= ((x - screen.last_x) / screenRenderInfo.scaleFactorX);
3485  screenRenderInfo.lowerLeftY += ((y - screen.last_y) / screenRenderInfo.scaleFactorY);
3486  callbacks_force_expose_event_for_screen ();
3487  callbacks_update_scrollbar_positions ();
3488  screen.last_x = x;
3489  screen.last_y = y;
3490  break;
3491  }
3492  case IN_ZOOM_OUTLINE: {
3493  if (screen.last_x || screen.last_y)
3494  render_draw_zoom_outline(screen.centered_outline_zoom);
3495  screen.last_x = x;
3496  screen.last_y = y;
3497  render_draw_zoom_outline(screen.centered_outline_zoom);
3498  break;
3499  }
3500  case IN_MEASURE: {
3501  /* clear the previous drawn line by drawing over it */
3503  callbacks_screen2board(&(screen.measure_stop_x),
3504  &(screen.measure_stop_y), x, y);
3505  /* screen.last_[xy] are updated to move the ruler pointers */
3506  screen.last_x = x;
3507  screen.last_y = y;
3508  /* draw the new line and write the new distance */
3510  break;
3511  }
3512  case IN_SELECTION_DRAG: {
3513  if (screen.last_x || screen.last_y)
3514  render_draw_selection_box_outline();
3515  screen.last_x = x;
3516  screen.last_y = y;
3517  render_draw_selection_box_outline();
3518  break;
3519  }
3520  default:
3521  screen.last_x = x;
3522  screen.last_y = y;
3523  break;
3524  }
3525  callbacks_update_statusbar_coordinates (x, y);
3526  callbacks_update_ruler_pointers ();
3527  return TRUE;
3528 } /* motion_notify_event */
3529 
3530 /* --------------------------------------------------------- */
3531 gboolean
3532 callbacks_drawingarea_button_press_event (GtkWidget *widget, GdkEventButton *event)
3533 {
3534  GdkWindow *drawing_area_window = screen.drawing_area->window;
3535  GdkCursor *cursor;
3536 
3537  switch (event->button) {
3538  case 1 :
3539  if (screen.tool == POINTER) {
3540  /* select */
3541  /* selection will only work with cairo, so do nothing if it's
3542  not compiled */
3543  screen.state = IN_SELECTION_DRAG;
3544  screen.start_x = event->x;
3545  screen.start_y = event->y;
3546  }
3547  else if (screen.tool == PAN) {
3548  /* Plain panning */
3549  screen.state = IN_MOVE;
3550  screen.last_x = event->x;
3551  screen.last_y = event->y;
3552  }
3553  else if (screen.tool == ZOOM) {
3554  screen.state = IN_ZOOM_OUTLINE;
3555  /* Zoom outline mode initiated */
3556  screen.start_x = event->x;
3557  screen.start_y = event->y;
3558  screen.centered_outline_zoom = event->state;
3559  }
3560  else if (screen.tool == MEASURE) {
3561  screen.state = IN_MEASURE;
3562  callbacks_screen2board(&(screen.measure_start_x), &(screen.measure_start_y),
3563  event->x, event->y);
3564  screen.measure_stop_x = screen.measure_start_x;
3565  screen.measure_stop_y = screen.measure_start_y;
3566  /* force an expose event to clear any previous measure lines */
3567  callbacks_force_expose_event_for_screen ();
3568  }
3569  break;
3570  case 2 :
3571  screen.state = IN_MOVE;
3572  screen.last_x = event->x;
3573  screen.last_y = event->y;
3574  cursor = gdk_cursor_new(GDK_FLEUR);
3575  gdk_window_set_cursor(drawing_area_window, cursor);
3576  gdk_cursor_destroy(cursor);
3577  break;
3578  case 3 :
3579  if (screen.tool == POINTER) {
3580  /* if no items are selected, try and find the item the user
3581  is pointing at */
3582  if (selection_length (&screen.selectionInfo) == 0) {
3583  gint index=callbacks_get_selected_row_index();
3584  if ((index >= 0) &&
3585  (index <= mainProject->last_loaded) &&
3586  (mainProject->file[index]->isVisible)) {
3587  render_fill_selection_buffer_from_mouse_click(
3588  event->x, event->y,
3589  index, SELECTION_REPLACE);
3590  } else {
3591  selection_clear (&screen.selectionInfo);
3592  update_selected_object_message (FALSE);
3593  render_refresh_rendered_image_on_screen ();
3594  }
3595  }
3596 
3597  /* only show the popup if we actually have something selected now */
3598  if (selection_length (&screen.selectionInfo) != 0) {
3599  update_selected_object_message (TRUE);
3600  gtk_menu_popup(GTK_MENU(screen.win.drawWindowPopupMenu), NULL, NULL, NULL, NULL,
3601  event->button, event->time);
3602  }
3603 
3604  } else {
3605  /* Zoom outline mode initiated */
3606  screen.state = IN_ZOOM_OUTLINE;
3607  screen.start_x = event->x;
3608  screen.start_y = event->y;
3609  screen.centered_outline_zoom = event->state & GDK_SHIFT_MASK;
3610  cursor = gdk_cursor_new(GDK_SIZING);
3611  gdk_window_set_cursor(drawing_area_window, cursor);
3612  gdk_cursor_destroy(cursor);
3613  }
3614  break;
3615  case 4 : /* Scroll wheel */
3616  render_zoom_display (ZOOM_IN_CMOUSE, 0, event->x, event->y);
3617  break;
3618  case 5 : /* Scroll wheel */
3619  render_zoom_display (ZOOM_OUT_CMOUSE, 0, event->x, event->y);
3620  break;
3621  default:
3622  break;
3623  }
3624  callbacks_switch_to_correct_cursor ();
3625  return TRUE;
3626 }
3627 
3628 static gboolean
3629 check_align_files_possibility (gerbv_selection_info_t *sel_info)
3630 {
3632  GtkMenuItem **menu_items = (GtkMenuItem **) screen.win.curEditAlingItem;
3633  gerbv_selection_item_t si[2];
3634  int id[2] = {-1, -1};
3635  int i;
3636 
3637  /* If has two objects, then can do files aligning */
3638  if (selection_length (sel_info) == 2) {
3639  si[0] = selection_get_item_by_index(sel_info, 0);
3640  si[1] = selection_get_item_by_index(sel_info, 1);
3641 
3642  for (i = 0; i <= mainProject->last_loaded; i++) {
3643  if (f[i]->image == si[0].image)
3644  id[0] = i;
3645 
3646  if (f[i]->image == si[1].image)
3647  id[1] = i;
3648  }
3649 
3650  /* Can align if on different files */
3651  if (id[0]*id[1] >= 0 && id[0] != id[1]) {
3652  gchar *str;
3653 
3654 /* TODO: add color boxes for layers as hint */
3655 
3656  /* Update align menu items */
3657  str = g_strdup_printf (_("#_%i %s > #%i %s"),
3658  id[0]+1, f[id[0]]->name,
3659  id[1]+1, f[id[1]]->name);
3660  gtk_menu_item_set_label (menu_items[0], str);
3661  g_free (str);
3662 
3663  str = g_strdup_printf (_("#_%i %s > #%i %s"),
3664  id[1]+1, f[id[1]]->name,
3665  id[0]+1, f[id[0]]->name);
3666  gtk_menu_item_set_label (menu_items[1], str);
3667  g_free (str);
3668 
3669  gtk_widget_set_sensitive (
3670  screen.win.curEditAlingMenuItem, TRUE);
3671 
3672  return TRUE;
3673  }
3674  }
3675 
3676  /* Can't align, disable align menu */
3677  gtk_widget_set_sensitive (screen.win.curEditAlingMenuItem, FALSE);
3678  gtk_menu_item_set_label (menu_items[0], "");
3679  gtk_menu_item_set_label (menu_items[1], "");
3680 
3681  return FALSE;
3682 }
3683 
3686 void
3688  GtkMenuItem *menu_item, gpointer user_data)
3689 {
3690  gerbv_fileinfo_t *fi[2];
3691  gerbv_selection_item_t item[2];
3692  gerbv_net_t *net;
3693  gerbv_selection_info_t *sel_info = &screen.selectionInfo;
3694  int align_second_to_first = GPOINTER_TO_INT(user_data);
3695  gdouble x[2], y[2];
3696  int i;
3697 
3698  if (selection_length (sel_info) != 2)
3699  return;
3700 
3701  item[0] = selection_get_item_by_index(sel_info, 0);
3702  item[1] = selection_get_item_by_index(sel_info, 1);
3703 
3704  fi[0] = gerbv_get_fileinfo_for_image (item[0].image, mainProject);
3705  fi[1] = gerbv_get_fileinfo_for_image (item[1].image, mainProject);
3706 
3707  if (fi[0] == NULL || fi[1] == NULL || fi[0] == fi[1])
3708  return;
3709 
3710  /* Calculate aligning coords */
3711  for (i = 0; i < 2; i++) {
3712  net = item[i].net;
3713 
3714  switch (net->aperture_state) {
3716  x[i] = net->stop_x;
3717  y[i] = net->stop_y;
3718  break;
3720  switch (net->interpolation) {
3725  x[i] = (net->stop_x + net->start_x)/2;
3726  y[i] = (net->stop_y + net->start_y)/2;
3727  break;
3730  x[i] = net->cirseg->cp_x;
3731  y[i] = net->cirseg->cp_y;
3732  break;
3733  default:
3734  GERB_COMPILE_ERROR (_("Can't align by this "
3735  "type of object"));
3736  return;
3737  }
3738  break;
3739  default:
3740  GERB_COMPILE_ERROR (_("Can't align by this "
3741  "type of object"));
3742  return;
3743  }
3744 
3745  gerbv_transform_coord_for_image(x + i, y + i,
3746  item[i].image, mainProject);
3747  }
3748 
3749  if (align_second_to_first) {
3750  fi[1]->transform.translateX += x[0] - x[1];
3751  fi[1]->transform.translateY += y[0] - y[1];
3752  } else {
3753  fi[0]->transform.translateX += x[1] - x[0];
3754  fi[0]->transform.translateY += y[1] - y[0];
3755  }
3756 
3757  render_refresh_rendered_image_on_screen ();
3758  callbacks_update_layer_tree ();
3759 }
3760 
3761 /* --------------------------------------------------------- */
3762 gboolean
3763 callbacks_drawingarea_button_release_event (GtkWidget *widget, GdkEventButton *event)
3764 {
3765  gint index;
3766 
3767  if (event->type != GDK_BUTTON_RELEASE)
3768  return TRUE;
3769 
3770  switch (screen.state) {
3771  case IN_MOVE:
3772  screen.off_x = 0;
3773  screen.off_y = 0;
3774  render_refresh_rendered_image_on_screen ();
3775  callbacks_switch_to_normal_tool_cursor (screen.tool);
3776  break;
3777 
3778  case IN_ZOOM_OUTLINE:
3779  if ((event->state & GDK_SHIFT_MASK) != 0) {
3780  render_zoom_display (ZOOM_OUT_CMOUSE, 0,
3781  event->x, event->y);
3782  }
3783  /* if the user just clicks without dragging, then simply
3784  zoom in a preset amount */
3786  else if ((fabs(screen.start_x - event->x) < 4.0) &&
3787  (fabs(screen.start_y - event->y) < 4.0)) {
3788  render_zoom_display (ZOOM_IN_CMOUSE, 0,
3789  event->x, event->y);
3790  } else {
3791  render_calculate_zoom_from_outline (widget, event);
3792  }
3793  callbacks_switch_to_normal_tool_cursor (screen.tool);
3794  break;
3795 
3796  case IN_SELECTION_DRAG:
3797  /* selection will only work with cairo, so do nothing if it's
3798  not compiled */
3800 
3801  if ((index >= 0) && mainProject->file[index]->isVisible) {
3802  enum selection_action sel_action = SELECTION_REPLACE;
3803 
3804  if (event->state & GDK_SHIFT_MASK)
3805  sel_action = SELECTION_ADD;
3806  else if (event->state & GDK_CONTROL_MASK)
3807  sel_action = SELECTION_TOGGLE;
3808 
3809  /* determine if this was just a click or a box drag */
3810  if ((fabs((double)(screen.last_x - screen.start_x)) < 5)
3811  && (fabs((double)(screen.last_y - screen.start_y)) < 5)) {
3812  render_fill_selection_buffer_from_mouse_click (
3813  event->x, event->y, index,
3814  sel_action);
3815  } else {
3816  render_fill_selection_buffer_from_mouse_drag (
3817  event->x, event->y,
3818  screen.start_x, screen.start_y,
3819  index, sel_action);
3820  }
3821 
3822  /* Check if anything was selected */
3823  update_selected_object_message (TRUE);
3824 
3825  check_align_files_possibility (&screen.selectionInfo);
3826  } else {
3827  render_refresh_rendered_image_on_screen ();
3828  }
3829  break;
3830  default:
3831  break;
3832  }
3833 
3834  screen.state = NORMAL;
3835 
3836  return TRUE;
3837 } /* button_release_event */
3838 
3839 /* --------------------------------------------------------- */
3840 gboolean
3841 callbacks_window_key_press_event (GtkWidget *widget, GdkEventKey *event)
3842 {
3843  switch (event->keyval) {
3844  case GDK_Escape:
3845  if (screen.tool == POINTER) {
3846  selection_clear (&screen.selectionInfo);
3847  update_selected_object_message (FALSE);
3848  }
3849 
3850  /* Escape may be used to abort outline zoom and just plain
3851  * repaint */
3852  screen.state = NORMAL;
3853  render_refresh_rendered_image_on_screen();
3854 
3855  break;
3856  default:
3857  break;
3858  }
3859 
3860  return TRUE;
3861 } /* key_press_event */
3862 
3863 /* --------------------------------------------------------- */
3864 gboolean
3865 callbacks_window_key_release_event (GtkWidget *widget, GdkEventKey *event)
3866 {
3867  return TRUE;
3868 } /* key_release_event */
3869 
3870 /* --------------------------------------------------------- */
3871 /* Scroll wheel */
3872 gboolean
3873 callbacks_window_scroll_event(GtkWidget *widget, GdkEventScroll *event)
3874 {
3875  switch (event->direction) {
3876  case GDK_SCROLL_UP:
3877  render_zoom_display (ZOOM_IN_CMOUSE, 0, event->x, event->y);
3878  break;
3879  case GDK_SCROLL_DOWN:
3880  render_zoom_display (ZOOM_OUT_CMOUSE, 0, event->x, event->y);
3881  break;
3882  case GDK_SCROLL_LEFT:
3883  /* Ignore */
3884  case GDK_SCROLL_RIGHT:
3885  /* Ignore */
3886  default:
3887  return TRUE;
3888  }
3889  return TRUE;
3890 } /* scroll_event */
3891 
3892 
3893 /* ------------------------------------------------------------------ */
3900 void
3902 {
3903  if (GTK_IS_LABEL(screen.win.statusMessageLeft)) {
3904  gtk_label_set_text(GTK_LABEL(screen.win.statusMessageLeft), screen.statusbar.coordstr);
3905  }
3906  if (GTK_IS_LABEL(screen.win.statusMessageRight)) {
3907  gtk_label_set_markup(GTK_LABEL(screen.win.statusMessageRight), screen.statusbar.diststr);
3908  }
3909 }
3910 
3911 /* --------------------------------------------------------- */
3912 void
3913 callbacks_update_statusbar_measured_distance (gdouble dx, gdouble dy){
3914  gdouble delta = hypot(dx, dy);
3915 
3916  if (screen.unit == GERBV_MILS) {
3917  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3918  _("Measured distance: %8.2f mils (%8.2f x, %8.2f y)"),
3919  COORD2MILS(delta), COORD2MILS(dx), COORD2MILS(dy));
3920  }
3921  else if (screen.unit == GERBV_MMS) {
3922  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3923  _("Measured distance: %8.3f mm (%8.3f x, %8.3f y)"),
3924  COORD2MMS(delta), COORD2MMS(dx), COORD2MMS(dy));
3925  }
3926  else {
3927  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3928  _("Measured distance: %4.5f inches (%4.5f x, %4.5f y)"),
3929  COORD2INS(delta), COORD2INS(dx), COORD2INS(dy));
3930  }
3932 }
3933 
3934 /* --------------------------------------------------------- */
3935 void
3936 callbacks_sidepane_render_type_combo_box_changed (GtkComboBox *widget, gpointer user_data) {
3937  gerbv_render_types_t type = gtk_combo_box_get_active (widget);
3938 
3939  DPRINTF("%s(): type = %d\n", __FUNCTION__, type);
3940 
3941  if (type < 0 || type == screenRenderInfo.renderType)
3942  return;
3943 
3944  screenRenderInfo.renderType = type;
3945  callbacks_render_type_changed ();
3946 }
3947 
3948 /* --------------------------------------------------------- */
3949 void
3950 callbacks_viewmenu_rendertype_changed (GtkCheckMenuItem *widget, gpointer user_data) {
3951  gerbv_render_types_t type = GPOINTER_TO_INT(user_data);
3952 
3953  if (type == screenRenderInfo.renderType)
3954  return;
3955 
3956  DPRINTF("%s(): type = %d\n", __FUNCTION__, type);
3957 
3958  screenRenderInfo.renderType = type;
3959  callbacks_render_type_changed ();
3960 }
3961 
3962 /* --------------------------------------------------------- */
3963 void
3964 callbacks_viewmenu_units_changed (GtkCheckMenuItem *widget, gpointer user_data) {
3965  gerbv_gui_unit_t unit = GPOINTER_TO_INT(user_data);
3966 
3967  if (unit < 0 || unit == screen.unit)
3968  return;
3969 
3970  DPRINTF("%s(): unit = %d, screen.unit = %d\n", __FUNCTION__, unit, screen.unit);
3971 
3972  callbacks_units_changed (unit);
3973 }
3974 
3975 /* --------------------------------------------------------- */
3976 void
3977 callbacks_statusbar_unit_combo_box_changed (GtkComboBox *widget, gpointer user_data) {
3978  gerbv_gui_unit_t unit = gtk_combo_box_get_active (widget);
3979  int force_change = GPOINTER_TO_INT (user_data);
3980 
3981  if (!force_change && (unit < 0 || unit == screen.unit))
3982  return;
3983 
3984  callbacks_units_changed (unit);
3985 }
3986 
3987 /* --------------------------------------------------------- */
3988 void
3989 callbacks_clear_messages_button_clicked (GtkButton *button, gpointer user_data) {
3990  GtkTextBuffer *textbuffer;
3991  GtkTextIter start, end;
3992 
3993  screen.length_sum = 0;
3994 
3995  textbuffer = gtk_text_view_get_buffer((GtkTextView*)screen.win.messageTextView);
3996  gtk_text_buffer_get_start_iter(textbuffer, &start);
3997  gtk_text_buffer_get_end_iter(textbuffer, &end);
3998  gtk_text_buffer_delete (textbuffer, &start, &end);
3999 }
4000 
4001 /* --------------------------------------------------------- */
4002 void
4003 callbacks_handle_log_messages(const gchar *log_domain, GLogLevelFlags log_level,
4004  const gchar *message, gpointer user_data)
4005 {
4006  GtkTextBuffer *textbuffer = NULL;
4007  GtkTextIter iter;
4008  GtkTextTag *tag;
4009  GtkTextMark *StartMark = NULL, *StopMark = NULL;
4010  GtkTextIter StartIter, StopIter;
4011  GtkWidget *dialog, *label;
4012 
4013  if (!screen.win.messageTextView)
4014  return;
4015 
4016  textbuffer = gtk_text_view_get_buffer((GtkTextView*)screen.win.messageTextView);
4017 
4018  /* create a mark for the end of the text. */
4019  gtk_text_buffer_get_end_iter(textbuffer, &iter);
4020 
4021  /* get the current end position of the text (it will be the
4022  start of the new text. */
4023  StartMark = gtk_text_buffer_create_mark(textbuffer,
4024  "NewTextStart", &iter, TRUE);
4025 
4026  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
4027  "blue_foreground");
4028  /* the tag does not exist: create it and let them exist in the tag table.*/
4029  if (tag == NULL) {
4030  tag = gtk_text_buffer_create_tag(textbuffer, "black_foreground",
4031  "foreground", "black", NULL);
4032  tag = gtk_text_buffer_create_tag(textbuffer, "blue_foreground",
4033  "foreground", "blue", NULL);
4034  tag = gtk_text_buffer_create_tag(textbuffer, "red_foreground",
4035  "foreground", "red", NULL);
4036  tag = gtk_text_buffer_create_tag(textbuffer, "darkred_foreground",
4037  "foreground", "darkred", NULL);
4038  tag = gtk_text_buffer_create_tag(textbuffer, "darkblue_foreground",
4039  "foreground", "darkblue", NULL);
4040  tag = gtk_text_buffer_create_tag (textbuffer, "darkgreen_foreground",
4041  "foreground", "darkgreen", NULL);
4042  tag = gtk_text_buffer_create_tag (textbuffer,
4043  "saddlebrown_foreground",
4044  "foreground", "saddlebrown", NULL);
4045  }
4046 
4047  /*
4048  * See rgb.txt for the color names definition
4049  * (on my PC it is on /usr/X11R6/lib/X11/rgb.txt)
4050  */
4051  switch (log_level & G_LOG_LEVEL_MASK) {
4052  case G_LOG_LEVEL_ERROR:
4053  /* a message of this kind aborts the application calling abort() */
4054  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
4055  "red_foreground");
4056  gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
4057  gtk_widget_show(screen.win.sidepane_notebook);
4058  break;
4059  case G_LOG_LEVEL_CRITICAL:
4060  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
4061  "red_foreground");
4062  gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
4063  gtk_widget_show(screen.win.sidepane_notebook);
4064  break;
4065  case G_LOG_LEVEL_WARNING:
4066  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
4067  "darkred_foreground");
4068  gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
4069  gtk_widget_show(screen.win.sidepane_notebook);
4070  break;
4071  case G_LOG_LEVEL_MESSAGE:
4072  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
4073  "darkblue_foreground");
4074  gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
4075  gtk_widget_show(screen.win.sidepane_notebook);
4076  break;
4077  case G_LOG_LEVEL_INFO:
4078  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
4079  "darkgreen_foreground");
4080  break;
4081  case G_LOG_LEVEL_DEBUG:
4082  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
4083  "saddlebrown_foreground");
4084  break;
4085  default:
4086  tag = gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table(textbuffer),
4087  "black_foreground");
4088  break;
4089  }
4090 
4091  /*
4092  * Fatal aborts application. We will try to get the message out anyhow.
4093  */
4094  if (log_level & G_LOG_FLAG_FATAL) {
4095  fprintf(stderr, _("Fatal error: %s\n"), message);
4096 
4097  /* Try to show dialog box with error message */
4098  dialog = gtk_dialog_new_with_buttons(_("Fatal Error"),
4099  NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4100  GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
4101 
4102  label = gtk_label_new(g_strdup_printf(_("Fatal error: %s"), message));
4103  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),
4104  label);
4105  gtk_label_set_selectable(GTK_LABEL(label), TRUE);
4106  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),
4107  gtk_label_new(_("\nGerbv will be closed now!")));
4108 
4109  gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
4110 
4111  gtk_widget_show_all(dialog);
4112  gtk_dialog_run(GTK_DIALOG(dialog));
4113  }
4114 
4115  gtk_text_buffer_insert(textbuffer, &iter, message, -1);
4116  gtk_text_buffer_insert(textbuffer, &iter, "\n", -1);
4117 
4118  /* Scroll view to inserted text */
4119  g_signal_emit_by_name(textbuffer, "paste-done", NULL);
4120 
4121  gtk_text_buffer_get_end_iter(textbuffer, &iter);
4122 
4123  StopMark = gtk_text_buffer_create_mark(textbuffer,
4124  "NewTextStop", &iter, TRUE);
4125 
4126  gtk_text_buffer_get_iter_at_mark(textbuffer, &StartIter, StartMark);
4127  gtk_text_buffer_get_iter_at_mark(textbuffer, &StopIter, StopMark);
4128 
4129  gtk_text_buffer_apply_tag(textbuffer, tag, &StartIter, &StopIter);
4130 }
4131 
4132 /* --------------------------------------------------------- */
4133 void callbacks_force_expose_event_for_screen (void)
4134 {
4135  GdkRectangle update_rect;
4136 
4137  update_rect.x = 0;
4138  update_rect.y = 0;
4139  update_rect.width = screenRenderInfo.displayWidth;
4140  update_rect.height = screenRenderInfo.displayHeight;
4141 
4142  /* Calls expose_event */
4143  gdk_window_invalidate_rect (screen.drawing_area->window, &update_rect, FALSE);
4144 
4145  /* update other gui things that could have changed */
4146  callbacks_update_ruler_scales ();
4147  callbacks_update_scrollbar_limits ();
4148  callbacks_update_scrollbar_positions ();
4149 }
4150 
4151 static double screen_units(double d)
4152 {
4153  switch (screen.unit) {
4154  case GERBV_INS:
4155  return COORD2INS(d);
4156  break;
4157  case GERBV_MILS:
4158  return COORD2MILS(d);
4159  break;
4160  case GERBV_MMS:
4161  return COORD2MMS(d);
4162  break;
4163  }
4164 
4165  return d;
4166 }
4167 
4168 static const char *screen_units_str(void)
4169 {
4170  /* NOTE: in order of gerbv_gui_unit_t */
4171  const char *units_str[] = {N_("mil"), N_("mm"), N_("in")};
4172 
4173  return _(units_str[screen.unit]);
4174 }
4175 
4176 static double line_length(double x0, double y0, double x1, double y1)
4177 {
4178  double dx = x0 - x1;
4179  double dy = y0 - y1;
4180 
4181  return hypot(dx, dy);
4182 }
4183 
4184 static double arc_length(double dia, double angle)
4185 {
4186  return M_PI*dia*(angle/360.0);
4187 }
4188 
4189 static void aperture_state_report (gerbv_net_t *net,
4190  gerbv_image_t *img, gerbv_project_t *prj)
4191 {
4192  gerbv_layertype_t layer_type = img->layertype;
4193 
4194  gboolean show_length = FALSE;
4195  gboolean aperture_is_valid = FALSE;
4196  double x, y, len = 0;
4197 
4198  if (net->aperture > 0)
4199  aperture_is_valid = TRUE;
4200 
4201  switch (net->aperture_state) {
4202 
4204  break;
4205 
4207  switch (net->interpolation) {
4208 
4213  if (layer_type != GERBV_LAYERTYPE_DRILL)
4214  g_message (_("Object type: Line"));
4215  else
4216  g_message (_("Object type: Slot (drilled)"));
4217 
4218  len = line_length(net->start_x, net->start_y,
4219  net->stop_x, net->stop_y);
4220  show_length = 1;
4221 
4222  break;
4223 
4226  g_message (_("Object type: Arc"));
4227  len = arc_length(net->cirseg->width,
4228  fabs(net->cirseg->angle1 -
4229  net->cirseg->angle2));
4230  show_length = 1;
4231 
4232  break;
4233  default:
4234  g_message (_("Object type: Unknown"));
4235  break;
4236  }
4237 
4238  if (layer_type != GERBV_LAYERTYPE_DRILL)
4239  g_message (_(" Exposure: On"));
4240 
4241  if (aperture_is_valid) {
4242  if (layer_type != GERBV_LAYERTYPE_DRILL)
4243  aperture_report(img->aperture, net->aperture,
4244  net->start_x, net->start_y,
4245  img, prj);
4246  else
4247  drill_report(img->aperture, net->aperture);
4248  }
4249 
4250  x = net->start_x;
4251  y = net->start_y;
4252  gerbv_transform_coord_for_image(&x, &y, img, prj);
4253  g_message (_(" Start: (%g, %g) %s"),
4254  screen_units(x),
4255  screen_units(y),
4256  screen_units_str());
4257 
4258  x = net->stop_x;
4259  y = net->stop_y;
4260  gerbv_transform_coord_for_image(&x, &y, img, prj);
4261  g_message (_(" Stop: (%g, %g) %s"),
4262  screen_units(x),
4263  screen_units(y),
4264  screen_units_str());
4265 
4266  switch (net->interpolation) {
4267 
4270  x = net->cirseg->cp_x;
4271  y = net->cirseg->cp_y;
4272  gerbv_transform_coord_for_image(&x, &y, img, prj);
4273  g_message (_(" Center: (%g, %g) %s"),
4274  screen_units(x),
4275  screen_units(y),
4276  screen_units_str());
4277 
4278  x = net->cirseg->width/2;
4279  y = x;
4280  gerbv_transform_coord_for_image(&x, &y, img, prj);
4281  g_message (_(" Radius: %g %s"),
4282  screen_units(x),
4283  screen_units_str());
4284 
4285  g_message (_(" Angle: %g deg"),
4286  fabs(net->cirseg->angle1 -
4287  net->cirseg->angle2));
4288  g_message (_(" Angles: (%g, %g) deg"),
4289  net->cirseg->angle1,
4290  net->cirseg->angle2);
4291  g_message (_(" Direction: %s"),
4292  (net->interpolation ==
4294  _("CW"): _("CCW"));
4295  break;
4296 
4297  default:
4298  break;
4299  }
4300 
4301  if (show_length) {
4302  gerbv_aperture_t *aper = img->aperture[net->aperture];
4303 
4304  if (layer_type == GERBV_LAYERTYPE_DRILL
4305  && aperture_is_valid
4306  && aper->type == GERBV_APTYPE_CIRCLE) {
4307  double dia = aper->parameter[0];
4308  g_message (_(" Slot length: %g %s"),
4309  screen_units(len + dia),
4310  screen_units_str());
4311  }
4312 
4313  screen.length_sum += len;
4314  g_message (_(" Length: %g (sum: %g) %s"),
4315  screen_units(len),
4316  screen_units(screen.length_sum),
4317  screen_units_str());
4318  }
4319 
4320  net_layer_file_report (net, img, prj);
4321 
4322  break;
4323 
4325  if (layer_type != GERBV_LAYERTYPE_DRILL)
4326  g_message (_("Object type: Flashed aperture"));
4327  else
4328  g_message (_("Object type: Drill"));
4329 
4330  if (aperture_is_valid) {
4331  if (layer_type != GERBV_LAYERTYPE_DRILL)
4332  aperture_report(img->aperture, net->aperture,
4333  net->stop_x, net->stop_y,
4334  img, prj);
4335  else
4336  drill_report(img->aperture, net->aperture);
4337  }
4338 
4339  x = net->stop_x;
4340  y = net->stop_y;
4341  gerbv_transform_coord_for_image(&x, &y, img, prj);
4342  g_message (_(" Location: (%g, %g) %s"),
4343  screen_units(x),
4344  screen_units(y),
4345  screen_units_str());
4346 
4347  net_layer_file_report (net, img, prj);
4348 
4349  break;
4350  }
4351 }
4352 
4353 static void
4354 aperture_report(gerbv_aperture_t *apertures[], int aperture_num,
4355  double x, double y, gerbv_image_t *img, gerbv_project_t *prj)
4356 {
4357  gerbv_aperture_type_t type = apertures[aperture_num]->type;
4358  double *params = apertures[aperture_num]->parameter;
4359  gerbv_simplified_amacro_t *sam = apertures[aperture_num]->simplified;
4360 
4361  g_message (_(" Aperture used: D%d"), aperture_num);
4362  g_message (_(" Aperture type: %s"),
4363  (type == GERBV_APTYPE_MACRO)?
4364  _(gerbv_aperture_type_name(sam->type)):
4365  _(gerbv_aperture_type_name(type)));
4366 
4367  switch (type) {
4368  case GERBV_APTYPE_CIRCLE:
4369  g_message (_(" Diameter: %g %s"),
4370  screen_units(params[0]),
4371  screen_units_str());
4372  break;
4374  case GERBV_APTYPE_OVAL:
4375  g_message (_(" Dimensions: %gx%g %s"),
4376  screen_units(params[0]),
4377  screen_units(params[1]),
4378  screen_units_str());
4379  break;
4380  case GERBV_APTYPE_MACRO: {
4381  switch (sam->type) {
4383  g_message (_(" Diameter: %g %s"),
4384  screen_units(sam->parameter[CIRCLE_DIAMETER]),
4385  screen_units_str());
4386  x += sam->parameter[CIRCLE_CENTER_X];
4387  y += sam->parameter[CIRCLE_CENTER_Y];
4388  gerbv_transform_coord_for_image(&x, &y, img, prj);
4389  g_message (_(" Center: (%g, %g) %s"),
4390  screen_units(x), screen_units(y),
4391  screen_units_str());
4392  break;
4393 
4395  g_message (_(" Number of points: %g"),
4396  sam->parameter[OUTLINE_NUMBER_OF_POINTS]);
4397  x += sam->parameter[OUTLINE_FIRST_X];
4398  y += sam->parameter[OUTLINE_FIRST_Y];
4399  gerbv_transform_coord_for_image(&x, &y, img, prj);
4400  g_message (_(" Start: (%g, %g) %s"),
4401  screen_units(x), screen_units(y),
4402  screen_units_str());
4403  g_message (_(" Rotation: %g deg"),
4404  sam->parameter[OUTLINE_ROTATION_IDX(sam->parameter)]);
4405  break;
4406 
4408  g_message (_(" Number of points: %g"),
4409  sam->parameter[POLYGON_NUMBER_OF_POINTS]);
4410  g_message (_(" Diameter: %g %s"),
4411  screen_units(sam->parameter[POLYGON_DIAMETER]),
4412  screen_units_str());
4413  x += sam->parameter[POLYGON_CENTER_X];
4414  y += sam->parameter[POLYGON_CENTER_Y];
4415  gerbv_transform_coord_for_image(&x, &y, img, prj);
4416  g_message (_(" Center: (%g, %g) %s"),
4417  screen_units(x), screen_units(y),
4418  screen_units_str());
4419  g_message (_(" Rotation: %g deg"),
4420  sam->parameter[POLYGON_ROTATION]);
4421  break;
4422 
4424  g_message (_(" Outside diameter: %g %s"),
4425  screen_units(sam->parameter[MOIRE_OUTSIDE_DIAMETER]),
4426  screen_units_str());
4427  g_message (_(" Ring thickness: %g %s"),
4428  screen_units(sam->parameter[MOIRE_CIRCLE_THICKNESS]),
4429  screen_units_str());
4430  g_message (_(" Gap width: %g %s"),
4431  screen_units(sam->parameter[MOIRE_GAP_WIDTH]),
4432  screen_units_str());
4433  g_message (_(" Number of rings: %g"),
4434  sam->parameter[MOIRE_NUMBER_OF_CIRCLES]);
4435  g_message (_(" Crosshair thickness: %g %s"),
4436  screen_units(
4437  sam->parameter[MOIRE_CROSSHAIR_THICKNESS]),
4438  screen_units_str());
4439  g_message (_(" Crosshair length: %g %s"),
4440  screen_units(sam->parameter[MOIRE_CROSSHAIR_LENGTH]),
4441  screen_units_str());
4442  x += sam->parameter[MOIRE_CENTER_X];
4443  y += sam->parameter[MOIRE_CENTER_Y];
4444  gerbv_transform_coord_for_image(&x, &y, img, prj);
4445  g_message (_(" Center: (%g, %g) %s"),
4446  screen_units(x), screen_units(y),
4447  screen_units_str());
4448  g_message (_(" Rotation: %g deg"),
4449  sam->parameter[MOIRE_ROTATION]);
4450  break;
4451 
4453  g_message (_(" Outside diameter: %g %s"),
4454  screen_units(sam->parameter[THERMAL_OUTSIDE_DIAMETER]),
4455  screen_units_str());
4456  g_message (_(" Inside diameter: %g %s"),
4457  screen_units(sam->parameter[THERMAL_INSIDE_DIAMETER]),
4458  screen_units_str());
4459  g_message (_(" Crosshair thickness: %g %s"),
4460  screen_units(
4461  sam->parameter[THERMAL_CROSSHAIR_THICKNESS]),
4462  screen_units_str());
4463  x += sam->parameter[THERMAL_CENTER_X];
4464  y += sam->parameter[THERMAL_CENTER_Y];
4465  gerbv_transform_coord_for_image(&x, &y, img, prj);
4466  g_message (_(" Center: (%g, %g) %s"),
4467  screen_units(x), screen_units(y),
4468  screen_units_str());
4469  g_message (_(" Rotation: %g deg"),
4470  sam->parameter[THERMAL_ROTATION]);
4471  break;
4472 
4474  g_message (_(" Width: %g %s"),
4475  screen_units(sam->parameter[LINE20_WIDTH]),
4476  screen_units_str());
4477  x += sam->parameter[LINE20_START_X];
4478  y += sam->parameter[LINE20_START_Y];
4479  gerbv_transform_coord_for_image(&x, &y, img, prj);
4480  g_message (_(" Start: (%g, %g) %s"),
4481  screen_units(x), screen_units(y),
4482  screen_units_str());
4483  x += sam->parameter[LINE20_END_X];
4484  y += sam->parameter[LINE20_END_Y];
4485  gerbv_transform_coord_for_image(&x, &y, img, prj);
4486  g_message (_(" Stop: (%g, %g) %s"),
4487  screen_units(x), screen_units(y),
4488  screen_units_str());
4489  g_message (_(" Rotation: %g deg"),
4490  sam->parameter[LINE20_ROTATION]);
4491  break;
4492 
4494  g_message (_(" Width: %g %s"),
4495  screen_units(sam->parameter[LINE21_WIDTH]),
4496  screen_units_str());
4497  g_message (_(" Height: %g %s"),
4498  screen_units(sam->parameter[LINE21_HEIGHT]),
4499  screen_units_str());
4500  x += sam->parameter[LINE21_CENTER_X];
4501  y += sam->parameter[LINE21_CENTER_Y];
4502  gerbv_transform_coord_for_image(&x, &y, img, prj);
4503  g_message (_(" Center: (%g, %g) %s"),
4504  screen_units(x), screen_units(y),
4505  screen_units_str());
4506  g_message (_(" Rotation: %g deg"),
4507  sam->parameter[LINE21_ROTATION]);
4508  break;
4509 
4511  g_message (_(" Width: %g %s"),
4512  screen_units(sam->parameter[LINE22_WIDTH]),
4513  screen_units_str());
4514  g_message (_(" Height: %g %s"),
4515  screen_units(sam->parameter[LINE22_HEIGHT]),
4516  screen_units_str());
4517  x += sam->parameter[LINE22_LOWER_LEFT_X];
4518  y += sam->parameter[LINE22_LOWER_LEFT_Y];
4519  gerbv_transform_coord_for_image(&x, &y, img, prj);
4520  g_message (_(" Lower left: (%g, %g) %s"),
4521  screen_units(x), screen_units(y),
4522  screen_units_str());
4523  g_message (_(" Rotation: %g deg"),
4524  sam->parameter[LINE22_ROTATION]);
4525  break;
4526 
4527  default:
4528  break;
4529  }
4530  break;
4531  }
4532  default:
4533  break;
4534  }
4535 }
4536 
4537 static void drill_report(gerbv_aperture_t *apertures[], int aperture_num)
4538 {
4539  gerbv_aperture_type_t type = apertures[aperture_num]->type;
4540  double *params = apertures[aperture_num]->parameter;
4541 
4542  g_message (_(" Tool used: T%d"), aperture_num);
4543  if (type == GERBV_APTYPE_CIRCLE)
4544  g_message (_(" Diameter: %g %s"),
4545  screen_units(params[0]),
4546  screen_units_str());
4547 }
4548 
4549 static void parea_report (gerbv_net_t *net,
4550  gerbv_image_t *img, gerbv_project_t *prj)
4551 {
4552  gerbv_net_t *n;
4553  unsigned int c = 0;
4554  gerbv_interpolation_t inter_prev;
4555  double x, y;
4556 
4558  return;
4559 
4560  /* Count vertices */
4561  for (gerbv_net_t *n = net->next; n != NULL; n = n->next) {
4563  break;
4564  c++;
4565  }
4566 
4567  g_message (_(" Number of vertices: %u"), c - 1);
4568 
4569  for (n = net->next, inter_prev = net->interpolation;
4570  n != NULL
4572  n = n->next) {
4573 
4574  switch (n->interpolation) {
4575 
4577 
4578  if (inter_prev != n->interpolation) {
4579  x = n->start_x;
4580  y = n->start_y;
4582  img, prj);
4583  g_message (_(" Line from: (%g, %g) %s"),
4584  screen_units(x),
4585  screen_units(y),
4586  screen_units_str());
4587  }
4588 
4589  x = n->stop_x;
4590  y = n->stop_y;
4591  gerbv_transform_coord_for_image(&x, &y, img, prj);
4592  g_message (_(" Line to: (%g, %g) %s"),
4593  screen_units(x), screen_units(y),
4594  screen_units_str());
4595  break;
4596 
4599 
4600  x = n->start_x;
4601  y = n->start_y;
4602  gerbv_transform_coord_for_image(&x, &y, img, prj);
4603  g_message (_(" Arc from: (%g, %g) %s"),
4604  screen_units(x), screen_units(y),
4605  screen_units_str());
4606 
4607  x = n->stop_x;
4608  y = n->stop_y;
4609  gerbv_transform_coord_for_image(&x, &y, img, prj);
4610  g_message (_(" Arc to: (%g, %g) %s"),
4611  screen_units(x), screen_units(y),
4612  screen_units_str());
4613 
4614  x = n->cirseg->cp_x;
4615  y = n->cirseg->cp_y;
4616  gerbv_transform_coord_for_image(&x, &y, img, prj);
4617  g_message (_(" Center: (%g, %g) %s"),
4618  screen_units(x), screen_units(y),
4619  screen_units_str());
4620 
4621  x = n->cirseg->width;
4622  y = n->cirseg->height;
4623  gerbv_transform_coord_for_image(&x, &y, img, prj);
4624  g_message (_(" Radius: %g %s"),
4625  screen_units(x)/2, screen_units_str());
4626 
4627  g_message (_(" Angle: %g deg"),
4628  fabs(n->cirseg->angle1 - n->cirseg->angle2));
4629  g_message (_(" Angles: (%g, %g) deg"),
4630  n->cirseg->angle1, n->cirseg->angle2);
4631  g_message (_(" Direction: %s"),
4632  (n->interpolation ==
4634  _("CW"): _("CCW"));
4635  break;
4636 
4637  default:
4638  g_message(" Skipping interpolation: %s",
4640  }
4641 
4642  inter_prev = n->interpolation;
4643  }
4644 }
4645 
4646 static void net_layer_file_report(gerbv_net_t *net,
4647  gerbv_image_t *img, gerbv_project_t *prj)
4648 {
4649  /* Don't report "no net" to keep log short */
4650  if (net->label != NULL)
4651  g_message (_(" Net label: %s"), net->label->str);
4652 
4653  /* Don't report "no layer name" to keep log short */
4654  if (net->layer->name != NULL)
4655  g_message (_(" Layer name: %s"), net->layer->name);
4656 
4657  /* Search file name in project files array */
4658  for (int i = 0; i <= prj->last_loaded; i++) {
4659  if (img == prj->file[i]->image)
4660  g_message (_(" In file: %s"), prj->file[i]->name);
4661  }
4662 }
4663 
4664 /* Restore report window size and postion */
4665 static void
4666 analyze_window_size_restore(GtkWidget *win)
4667 {
4668  GVariant *var;
4669  const gint32 *xy;
4670  gsize num;
4671 
4672  if (!screen.settings)
4673  return;
4674 
4675  var = g_settings_get_value (screen.settings, "analyze-window-size");
4676  xy = g_variant_get_fixed_array (var, &num, sizeof (*xy));
4677  if (num == 2)
4678  gtk_window_set_default_size (GTK_WINDOW (win), xy[0], xy[1]);
4679  g_variant_unref (var);
4680 
4681  var = g_settings_get_value (screen.settings, "analyze-window-position");
4682  xy = g_variant_get_fixed_array (var, &num, sizeof (*xy));
4683  if (num == 2)
4684  gtk_window_move (GTK_WINDOW (win), xy[0], xy[1]);
4685  g_variant_unref (var);
4686 }
4687 
4688 /* Store report window size and postion */
4689 static void
4690 analyze_window_size_store(GtkWidget *win, gpointer user_data)
4691 {
4692  gint32 xy[2];
4693  GVariant *var;
4694  gboolean is_max;
4695 
4696  if (!screen.settings)
4697  return;
4698 
4699  is_max = FALSE != (GDK_WINDOW_STATE_MAXIMIZED &
4700  gdk_window_get_state (gtk_widget_get_window (win)));
4701  if (is_max)
4702  return;
4703 
4704  gtk_window_get_size (GTK_WINDOW (win), (gint *)xy, (gint *)(xy+1));
4705  var = g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
4706  xy, 2, sizeof (xy[0]));
4707  g_settings_set_value (screen.settings, "analyze-window-size", var);
4708 
4709  gtk_window_get_position (GTK_WINDOW (win),
4710  (gint *)xy, (gint *)(xy+1));
4711  var = g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
4712  xy, 2, sizeof (xy[0]));
4713  g_settings_set_value (screen.settings, "analyze-window-position", var);
4714 }
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:1977
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:1814
void callbacks_update_statusbar(void)
Displays additional information in the statusbar.
Definition: callbacks.c:3901
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:3687
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:2418
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:3763
void callbacks_about_activate(GtkMenuItem *menuitem, gpointer user_data)
The help -> about menu item was selected.
Definition: callbacks.c:1881
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:2510
const char * drill_m_code_name(drill_m_code_t m_code)
Return drill M-code name by code number.
Definition: drill.c:2584
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:958
void gerbv_image_delete_net(gerbv_net_t *currentNet)
Delete a net in an existing image.
Definition: gerb_image.c:1002
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:920
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:2729
const char * gerber_g_code_name(int g_code)
Return Gerber G-code name by code number.
Definition: gerber.c:2740
const char * gerber_m_code_name(int m_code)
Return Gerber M-code name by code number.
Definition: gerber.c:2766
const char * gerbv_interpolation_name(gerbv_interpolation_t interp)
Return string name of gerbv_interpolation_t interpolation.
Definition: gerbv.c:115
gerbv_fileinfo_t * gerbv_get_fileinfo_for_image(const gerbv_image_t *image, const gerbv_project_t *project)
Definition: gerbv.c:1130
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:242
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:781
int gerbv_transform_coord_for_image(double *x, double *y, const gerbv_image_t *image, const gerbv_project_t *project)
Definition: gerbv.c:1173
The main header file for the libgerbv library.
@ GERBV_APERTURE_STATE_OFF
Definition: gerbv.h:178
@ GERBV_APERTURE_STATE_ON
Definition: gerbv.h:179
@ GERBV_APERTURE_STATE_FLASH
Definition: gerbv.h:180
gerbv_render_types_t
Definition: gerbv.h:367
@ GERBV_RENDER_TYPE_CAIRO_HIGH_QUALITY
Definition: gerbv.h:370
@ GERBV_RENDER_TYPE_GDK_XOR
Definition: gerbv.h:368
@ GERBV_RENDER_TYPE_GDK
Definition: gerbv.h:367
@ GERBV_RENDER_TYPE_CAIRO_NORMAL
Definition: gerbv.h:369
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:302
@ GERBV_INTERPOLATION_LINEARx01
Definition: gerbv.h:304
@ GERBV_INTERPOLATION_PAREA_START
Definition: gerbv.h:308
@ GERBV_INTERPOLATION_LINEARx001
Definition: gerbv.h:305
@ GERBV_INTERPOLATION_CW_CIRCULAR
Definition: gerbv.h:306
@ GERBV_INTERPOLATION_PAREA_END
Definition: gerbv.h:309
@ GERBV_INTERPOLATION_LINEARx10
Definition: gerbv.h:303
@ GERBV_INTERPOLATION_CCW_CIRCULAR
Definition: gerbv.h:307
@ GERBV_INTERPOLATION_LINEARx1
Definition: gerbv.h:302
gerbv_layertype_t
Definition: gerbv.h:327
@ GERBV_LAYERTYPE_RS274X
Definition: gerbv.h:328
@ GERBV_LAYERTYPE_DRILL
Definition: gerbv.h:329
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:906
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:738
gchar * fullPathname
Definition: gerbv.h:741
gerbv_image_t * image
Definition: gerbv.h:736
gerbv_user_transformation_t transform
Definition: gerbv.h:743
gchar * name
Definition: gerbv.h:742
GdkColor color
Definition: gerbv.h:737
gboolean layer_dirty
Definition: gerbv.h:744
gboolean isVisible
Definition: gerbv.h:739
gerbv_layertype_t layertype
Definition: gerbv.h:722
gerbv_aperture_t * aperture[APERTURE_MAX]
Definition: gerbv.h:723
gerbv_image_info_t * info
Definition: gerbv.h:728
gchar * name
Definition: gerbv.h:639
gerbv_layer_t * layer
Definition: gerbv.h:668
double stop_y
Definition: gerbv.h:660
GString * label
Definition: gerbv.h:667
gerbv_aperture_state_t aperture_state
Definition: gerbv.h:663
double stop_x
Definition: gerbv.h:659
double start_x
Definition: gerbv.h:657
struct gerbv_net * next
Definition: gerbv.h:666
double start_y
Definition: gerbv.h:658
gerbv_interpolation_t interpolation
Definition: gerbv.h:664
gerbv_cirseg_t * cirseg
Definition: gerbv.h:665
int aperture
Definition: gerbv.h:662
gboolean use_cairo_svg
Definition: gerbv.h:762
gerbv_fileinfo_t ** file
Definition: gerbv.h:752
gchar * project
Definition: gerbv.h:761
gboolean show_invisible_selection
Definition: gerbv.h:757
GdkColor background
Definition: gerbv.h:750
gboolean check_before_delete
Definition: gerbv.h:756
gchar * path
Definition: gerbv.h:758
int max_files
Definition: gerbv.h:751
int last_loaded
Definition: gerbv.h:754
gdouble lowerLeftY
Definition: gerbv.h:778
gboolean show_cross_on_drill_holes
Definition: gerbv.h:782
gdouble scaleFactorX
Definition: gerbv.h:775
gint displayHeight
Definition: gerbv.h:781
gdouble lowerLeftX
Definition: gerbv.h:777
gerbv_render_types_t renderType
Definition: gerbv.h:779
gdouble scaleFactorY
Definition: gerbv.h:776
Header info for GTK widgets table functions.