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