gerbv  2.6A
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 
31 #if !defined(WIN32) && !defined(QUARTZ)
32 # include <gdk/gdkx.h>
33 #endif
34 
35 #ifdef HAVE_STDLIB_H
36 #include <stdlib.h>
37 #endif
38 
39 #ifdef HAVE_STRING_H
40 #include <string.h>
41 #endif
42 
43 #ifdef HAVE_TIME_H
44 #include <time.h>
45 #endif
46 
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50 
51 #include <math.h>
52 #include "common.h"
53 #include "main.h"
54 #include "callbacks.h"
55 #include "interface.h"
56 #include "attribute.h"
57 #include "render.h"
58 #include "table.h"
59 
60 #include "draw-gdk.h"
61 
62 #include "draw.h"
63 #ifdef WIN32
64 # include <cairo-win32.h>
65 #elif QUARTZ
66 # include <cairo-quartz.h>
67 #else
68 # include <cairo-xlib.h>
69 #endif
70 
71 
72 #define dprintf if(DEBUG) printf
73 
74 /* This default extension should really not be changed, but if it absolutely
75  * must change, the ../win32/gerbv.nsi.in *must* be changed to reflect that.
76  * Just grep for the extension (gvp) and change it in two places in that file.
77  */
78 #define GERBV_PROJECT_FILE_NAME N_("Gerbv Project")
79 #define GERBV_PROJECT_FILE_EXT ".gvp"
80 #define GERBV_PROJECT_FILE_PAT "*.gvp"
81 
85 extern gerbv_screen_t screen;
86 extern gerbv_render_info_t screenRenderInfo;
87 
88 
89 /* These are the names of the valid apertures. These
90  * values are used in several places in this file.
91  * Please keep this in sync with the gerbv_aperture_type_t
92  * enum defined in gerbv.h */
93 char *aperture_names[] = {"NONE",
94  "CIRCLE",
95  "RECTANGLE",
96  "OVAL", /* an ovular (obround) aperture */
97  "POLYGON", /* a polygon aperture */
98  "MACRO", /* a RS274X macro */
99  "MACRO_CIRCLE", /* a RS274X circle macro */
100  "MACRO_OUTLINE", /* a RS274X outline macro */
101  "MACRO_POLYGON", /* a RS274X polygon macro */
102  "MACRO_MOIRE", /* a RS274X moire macro */
103  "MACRO_THERMAL", /* a RS274X thermal macro */
104  "MACRO_LINE20", /* a RS274X line (code 20) macro */
105  "MACRO_LINE21", /* a RS274X line (code 21) macro */
106  "MACRO_LINE22" /* a RS274X line (code 22) macro */
107 };
108 
109 static gint callbacks_get_selected_row_index (void);
110 static void callbacks_units_changed (gerbv_gui_unit_t unit);
111 static void callbacks_update_statusbar_coordinates (gint x, gint y);
112 static void callbacks_update_ruler_scales (void);
113 static void callbacks_render_type_changed (void);
114 static void show_no_layers_warning (void);
115 static double screen_units(double);
116 static double line_length(double, double, double, double);
117 static double arc_length(double, double);
118 static void aperture_report(gerbv_aperture_t *[], int);
119 
120 
121 gchar *utf8_strncpy(gchar *dst, const gchar *src, gsize byte_len)
122 {
123  /* -1 for '\0' in buffer */
124  glong char_len = g_utf8_strlen(src, byte_len - 1);
125  return g_utf8_strncpy(dst, src, char_len);
126 }
127 
128 void utf8_snprintf(gchar *dst, gsize byte_len, const gchar *fmt, ...)
129 {
130  va_list ap;
131 
132  va_start(ap, fmt);
133  gchar *str = g_strdup_vprintf(fmt, ap);
134  utf8_strncpy(dst, str, byte_len);
135  g_free(str);
136 }
137 
138 /* --------------------------------------------------------- */
139 
140 static void show_no_layers_warning (void) {
141  gchar *str = g_new(gchar, MAX_DISTLEN);
142  utf8_strncpy(str, _("No layers are currently loaded. A layer must be loaded first."), MAX_DISTLEN - 7);
143  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN, "<b>%s</b>", str);
144  g_free(str);
145 
147 }
148 
149 /* --------------------------------------------------------- */
155 void
156 callbacks_new_activate (GtkMenuItem *menuitem, gpointer user_data)
157 {
158  if (mainProject->last_loaded >= 0) {
160  _("Do you want to close any open layers and start a new project?"),
161  _("Starting a new project will cause all currently open layers to be closed. Any unsaved changes will be lost."),
162  FALSE,
163  NULL))
164  return;
165  }
166  /* Unload all layers and then clear layer window */
167  gerbv_unload_all_layers (mainProject);
168  callbacks_update_layer_tree ();
169  render_clear_selection_buffer ();
170 
171  /* Destroy project info */
172  if (mainProject->project) {
173  g_free(mainProject->project);
174  mainProject->project = NULL;
175  }
176  render_refresh_rendered_image_on_screen();
177 }
178 
179 
180 /* --------------------------------------------------------- */
186 void
187 callbacks_open_project_activate (GtkMenuItem *menuitem,
188  gpointer user_data)
189 {
190  gchar *filename=NULL;
191  GtkFileFilter * filter;
192 
193  if (mainProject->last_loaded >= 0) {
195  _("Do you want to close any open layers and load an existing project?"),
196  _("Loading a project will cause all currently open layers to be closed. Any unsaved changes will be lost."),
197  FALSE,
198  NULL))
199  return;
200  }
201 
202  screen.win.gerber =
203  gtk_file_chooser_dialog_new (_("Open project file..."),
204  NULL,
205  GTK_FILE_CHOOSER_ACTION_OPEN,
206  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
207  GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
208  NULL);
209  gtk_file_chooser_set_current_folder ((GtkFileChooser *) screen.win.gerber,
210  mainProject->path);
211 
212  filter = gtk_file_filter_new();
213  gtk_file_filter_set_name(filter, _(GERBV_PROJECT_FILE_NAME));
214  gtk_file_filter_add_pattern(filter, GERBV_PROJECT_FILE_PAT);
215  gtk_file_chooser_add_filter ((GtkFileChooser *) screen.win.gerber,
216  filter);
217 
218  filter = gtk_file_filter_new();
219  gtk_file_filter_set_name(filter, _("All"));
220  gtk_file_filter_add_pattern(filter, "*");
221  gtk_file_chooser_add_filter ((GtkFileChooser *) screen.win.gerber,
222  filter);
223 
224  gtk_widget_show (screen.win.gerber);
225  if (gtk_dialog_run ((GtkDialog*)screen.win.gerber) == GTK_RESPONSE_ACCEPT) {
226  filename =
227  gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (screen.win.gerber));
228  /* update the last folder */
229  g_free (mainProject->path);
230  mainProject->path = gtk_file_chooser_get_current_folder ((GtkFileChooser *) screen.win.gerber);
231  }
232  gtk_widget_destroy (screen.win.gerber);
233 
234  if (filename) {
235  gerbv_unload_all_layers (mainProject);
236  main_open_project_from_filename (mainProject, filename);
237  }
238  gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
239  render_refresh_rendered_image_on_screen();
240  callbacks_update_layer_tree();
241 
242  return;
243 }
244 
245 
246 /* --------------------------------------------------------- */
252 void
253 callbacks_open_layer_activate (GtkMenuItem *menuitem,
254  gpointer user_data)
255 {
256  GSList *filenames=NULL;
257  GSList *filename=NULL;
258 
259  screen.win.gerber =
260  gtk_file_chooser_dialog_new (_("Open Gerber, drill, or pick & place file(s)..."),
261  NULL,
262  GTK_FILE_CHOOSER_ACTION_OPEN,
263  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
264  GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
265  NULL);
266 
267  gtk_file_chooser_set_select_multiple((GtkFileChooser *) screen.win.gerber, TRUE);
268  gtk_file_chooser_set_current_folder ((GtkFileChooser *) screen.win.gerber,
269  mainProject->path);
270  gtk_widget_show (screen.win.gerber);
271  if (gtk_dialog_run ((GtkDialog*)screen.win.gerber) == GTK_RESPONSE_ACCEPT) {
272  filenames =
273  gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER (screen.win.gerber));
274  /* update the last folder */
275  g_free (mainProject->path);
276  mainProject->path = gtk_file_chooser_get_current_folder ((GtkFileChooser *) screen.win.gerber);
277  }
278  gtk_widget_destroy (screen.win.gerber);
279 
280  /* Now try to open all gerbers specified */
281  for (filename=filenames; filename; filename=filename->next) {
283  }
284  g_slist_free(filenames);
285 
286  gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
287  render_refresh_rendered_image_on_screen();
288  callbacks_update_layer_tree();
289 
290  return;
291 }
292 
293 /* --------------------------------------------------------- */
294 void
295 callbacks_revert_activate (GtkMenuItem *menuitem,
296  gpointer user_data)
297 {
298  gerbv_revert_all_files (mainProject);
299  render_clear_selection_buffer();
300  callbacks_update_selected_object_message(FALSE);
301  render_refresh_rendered_image_on_screen();
302  callbacks_update_layer_tree();
303 }
304 
305 /* --------------------------------------------------------- */
306 void
307 callbacks_save_project_activate (GtkMenuItem *menuitem,
308  gpointer user_data)
309 {
310  if (mainProject->project)
311  main_save_project_from_filename (mainProject, mainProject->project);
312  else
313  callbacks_generic_save_activate (menuitem, (gpointer) CALLBACKS_SAVE_PROJECT_AS);
314  callbacks_update_layer_tree();
315  return;
316 }
317 
318 /* --------------------------------------------------------- */
319 void
320 callbacks_save_layer_activate (GtkMenuItem *menuitem,
321  gpointer user_data)
322 {
323  /* first figure out which layer in the layer side menu is selected */
325 
326  /* Now save that layer */
327  if (index >= 0) {
328  if (!gerbv_save_layer_from_index (mainProject, index, mainProject->file[index]->fullPathname)) {
329  interface_show_alert_dialog(_("Gerbv cannot export this file type"),
330  NULL,
331  FALSE,
332  NULL);
333  mainProject->file[index]->layer_dirty = FALSE;
334  callbacks_update_layer_tree();
335  return;
336  }
337  }
338  callbacks_update_layer_tree();
339  return;
340 }
341 struct l_image_info {
342  gerbv_image_t *image;
343  gerbv_user_transformation_t *transform;
344 };
345 
346 /* --------------------------------------------------------- */
351 {
352  gint i, filecount, img;
353  gerbv_image_t *out;
354  struct l_image_info {
355  gerbv_image_t *image;
356  gerbv_user_transformation_t *transform;
357  } *images;
358 
359  images=(struct l_image_info *)g_new0(struct l_image_info,1);
360  out = NULL;
361  switch(type){
362  case CALLBACKS_SAVE_FILE_DRILLM:
364  break;
365  case CALLBACKS_SAVE_FILE_RS274XM:
367  break;
368  default:
369  GERB_MESSAGE(_("Unknown Layer type for merge"));
370  goto err;
371  }
372  dprintf(_("Looking for matching files\n"));
373  for (i = img = filecount = 0; i < mainProject->max_files; ++i) {
374  if (mainProject->file[i] && mainProject->file[i]->isVisible &&
375  (mainProject->file[i]->image->layertype == type)) {
376  ++filecount;
377  dprintf(_("Adding '%s'\n"),mainProject->file[i]->name);
378  images[img].image=mainProject->file[i]->image;
379  images[img++].transform=&mainProject->file[i]->transform;
380  images = (struct l_image_info *)g_renew(struct l_image_info, images, img+1);
381  }
382  }
383  if (filecount < 2) {
384  GERB_MESSAGE (_("Not Enough Files of same type to merge"));
385  goto err;
386  }
387  dprintf(_("Now merging files\n"));
388  for (i = 0; i < img; ++i) {
389  gerbv_user_transformation_t *thisTransform;
390  gerbv_user_transformation_t identityTransform = {0,0,1,1,0,FALSE,FALSE,FALSE};
391  thisTransform=images[i].transform;
392  if (NULL == thisTransform)
393  thisTransform = &identityTransform;
394  if (0 == i)
395  out = gerbv_image_duplicate_image(images[i].image, thisTransform);
396  else
397  gerbv_image_copy_image(images[i].image, thisTransform, out);
398  }
399 err:
400  g_free(images);
401  return out;
402 }
403 
404 /* --------------------------------------------------------- */
405 void
406 callbacks_generic_save_activate (GtkMenuItem *menuitem,
407  gpointer user_data)
408 {
409  gchar *filename = NULL;
410  gchar *windowTitle = NULL;
411  gint processType = GPOINTER_TO_INT (user_data);
412  GtkFileFilter *filter;
413  GtkSpinButton *spin_but;
414  gint spin_but_val;
415  GtkTooltips *tooltips;
416  GtkWidget *label;
417  GtkWidget *hbox;
418  static gint dpi;
419 
420  gint index = callbacks_get_selected_row_index ();
421  if (index < 0) {
422  interface_show_alert_dialog (_("No layer is currently selected"),
423  _("Please select a layer and try again."),
424  FALSE,
425  NULL);
426  return;
427  }
428 
429  screen.win.gerber =
430  gtk_file_chooser_dialog_new ("", NULL,
431  GTK_FILE_CHOOSER_ACTION_SAVE,
432  NULL, NULL, NULL);
433  GtkFileChooser *file_chooser_p =
434  GTK_FILE_CHOOSER(screen.win.gerber);
435  gtk_file_chooser_set_do_overwrite_confirmation (file_chooser_p, TRUE);
436 
437  hbox = gtk_hbox_new (0, 0);
438  spin_but = GTK_SPIN_BUTTON(gtk_spin_button_new_with_range (0, 0, 1));
439  label = gtk_label_new ("");
440  tooltips = gtk_tooltips_new ();
441  gtk_box_pack_end (GTK_BOX(hbox), GTK_WIDGET(spin_but), 0, 0, 1);
442  gtk_box_pack_end (GTK_BOX(hbox), label, 0, 0, 5);
443  gtk_box_pack_end (GTK_BOX(GTK_DIALOG(screen.win.gerber)->vbox),
444  hbox, 0, 0, 2);
445 
446  if (processType == CALLBACKS_SAVE_PROJECT_AS)
447  windowTitle = g_strdup (_("Save project as..."));
448  else if (processType == CALLBACKS_SAVE_FILE_PS)
449  windowTitle = g_strdup (_("Export PS file as..."));
450  else if (processType == CALLBACKS_SAVE_FILE_PDF)
451  windowTitle = g_strdup (_("Export PDF file as..."));
452  else if (processType == CALLBACKS_SAVE_FILE_SVG)
453  windowTitle = g_strdup (_("Export SVG file as..."));
454  else if (processType == CALLBACKS_SAVE_FILE_PNG) {
455  windowTitle = g_strdup (_("Export PNG file as..."));
456  gtk_label_set_text (GTK_LABEL(label), _("DPI:"));
457  gtk_spin_button_set_range (spin_but, 0, 6000);
458  gtk_spin_button_set_increments (spin_but, 10, 100);
459  gtk_tooltips_set_tip (tooltips, GTK_WIDGET(label),
460  _("DPI value, autoscaling if 0"), NULL);
461  gtk_tooltips_set_tip (tooltips, GTK_WIDGET(spin_but),
462  _("DPI value, autoscaling if 0"), NULL);
463  gtk_spin_button_set_value (spin_but, dpi);
464  gtk_widget_show_all (hbox);
465  } else if (processType == CALLBACKS_SAVE_FILE_RS274X)
466  windowTitle = g_strdup (_("Export RS-274X file as..."));
467  else if (processType == CALLBACKS_SAVE_FILE_DRILL)
468  windowTitle = g_strdup (_("Export Excellon drill file as..."));
469  else if (processType == CALLBACKS_SAVE_FILE_RS274XM)
470  windowTitle = g_strdup (_("Export RS-274Xm file as..."));
471  else if (processType == CALLBACKS_SAVE_FILE_DRILLM)
472  windowTitle = g_strdup (_("Export Excellon drillm file as..."));
473  else if (processType == CALLBACKS_SAVE_LAYER_AS)
474  windowTitle = g_strdup (_("Save layer as..."));
475 
476  gtk_dialog_add_buttons (GTK_DIALOG(screen.win.gerber),
477  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
478  GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
479  NULL);
480 
481  gtk_window_set_title (GTK_WINDOW(screen.win.gerber), windowTitle);
482  g_free (windowTitle);
483 
484  /* if we're saving or exporting a layer, start off in the location of the
485  loaded file */
486  if (processType != CALLBACKS_SAVE_PROJECT_AS) {
487  gint index=callbacks_get_selected_row_index ();
488  if (index >= 0) {
489  gchar *dirName = g_path_get_dirname (mainProject->file[index]->fullPathname);
490  gtk_file_chooser_set_current_folder (file_chooser_p, dirName);
491  g_free (dirName);
492  }
493  }
494 
495  if (processType == CALLBACKS_SAVE_PROJECT_AS) {
496  filter = gtk_file_filter_new ();
497  gtk_file_filter_set_name (filter, _(GERBV_PROJECT_FILE_NAME));
498  gtk_file_filter_add_pattern (filter, GERBV_PROJECT_FILE_PAT);
499  gtk_file_chooser_add_filter (file_chooser_p, filter);
500 
501  filter = gtk_file_filter_new ();
502  gtk_file_filter_set_name (filter, _("All"));
503  gtk_file_filter_add_pattern (filter, "*");
504  gtk_file_chooser_add_filter (file_chooser_p, filter);
505 
506  gtk_file_chooser_set_current_name (file_chooser_p,
507  "untitled" GERBV_PROJECT_FILE_EXT);
508  }
509 
510  gtk_widget_show (screen.win.gerber);
511  if (gtk_dialog_run (GTK_DIALOG(screen.win.gerber)) == GTK_RESPONSE_ACCEPT) {
512  filename = gtk_file_chooser_get_filename (file_chooser_p);
513  spin_but_val = gtk_spin_button_get_value_as_int (spin_but);
514  }
515  gtk_widget_destroy (screen.win.gerber);
516 
517  if (filename) {
518  if (processType == CALLBACKS_SAVE_PROJECT_AS) {
519  main_save_as_project_from_filename (mainProject, filename);
520  rename_main_window(filename, NULL);
521  }
522  else if (processType == CALLBACKS_SAVE_FILE_PS)
524  else if (processType == CALLBACKS_SAVE_FILE_PDF)
526  else if (processType == CALLBACKS_SAVE_FILE_SVG)
528  else if (processType == CALLBACKS_SAVE_FILE_PNG) {
529  dpi = spin_but_val;
530  if (dpi == 0) {
532  screenRenderInfo.displayWidth, screenRenderInfo.displayHeight,
533  filename);
534  } else { /* Non zero DPI */
536  gerbv_render_get_boundingbox (mainProject, &bb);
537  gfloat w = bb.right - bb.left;
538  gfloat h = bb.bottom - bb.top;
539  gerbv_render_info_t renderInfo = {
540  dpi, dpi,
541  bb.left - (w*GERBV_DEFAULT_BORDER_COEFF)/2.0,
542  bb.top - (h*GERBV_DEFAULT_BORDER_COEFF)/2.0,
544  w*dpi*(1 + GERBV_DEFAULT_BORDER_COEFF),
545  h*dpi*(1 + GERBV_DEFAULT_BORDER_COEFF),
546  };
548  &renderInfo, filename);
549  }
550  } else if (processType == CALLBACKS_SAVE_LAYER_AS) {
551  gint index=callbacks_get_selected_row_index ();
552 
553  gerbv_save_layer_from_index (mainProject, index, filename);
554  /* rename the file path in the index, so future saves will reference the new file path */
555  g_free (mainProject->file[index]->fullPathname);
556  mainProject->file[index]->fullPathname = g_strdup (filename);
557  g_free (mainProject->file[index]->name);
558  mainProject->file[index]->name = g_path_get_basename (filename);
559  }
560  else if (processType == CALLBACKS_SAVE_FILE_RS274X) {
561  gint index=callbacks_get_selected_row_index ();
562 
564  &mainProject->file[index]->transform);
565  }
566  else if (processType == CALLBACKS_SAVE_FILE_DRILL) {
567  gint index=callbacks_get_selected_row_index ();
568 
570  &mainProject->file[index]->transform);
571  } /* create new image.... */
572  else if (processType == CALLBACKS_SAVE_FILE_RS274XM) {
573  gerbv_image_t *image;
574  gerbv_user_transformation_t t = {0,0,1,1,0,FALSE,FALSE,FALSE};
575  if (NULL != (image=merge_images (processType)) ){
576  gerbv_export_rs274x_file_from_image (filename, image, &t);
577  gerbv_destroy_image (image);
578  GERB_MESSAGE (_("Merged visible gerber layers and placed in '%s'"),filename);
579  }
580  }
581  else if (processType == CALLBACKS_SAVE_FILE_DRILLM) {
582  gerbv_image_t *image;
583  gerbv_user_transformation_t t = {0,0,1,1,0,FALSE,FALSE,FALSE};
584  if (NULL != (image = merge_images (processType))) {
585  gerbv_export_drill_file_from_image (filename, image,&t);
586  gerbv_destroy_image (image);
587  GERB_MESSAGE (_("Merged visible drill layers and placed in '%s'"),filename);
588  }
589  }
590  }
591  g_free (filename);
592  callbacks_update_layer_tree ();
593  return;
594 }
595 
596 /* --------------------------------------------------------- */
597 #if GTK_CHECK_VERSION(2,10,0)
598 
599 static void
600 callbacks_begin_print (GtkPrintOperation *operation, GtkPrintContext *context,
601  gpointer user_data) {
602  gtk_print_operation_set_n_pages (operation, 1);
603 }
604 
605 
606 /* --------------------------------------------------------- */
607 static void
608 callbacks_print_render_page (GtkPrintOperation *operation,
609  GtkPrintContext *context,
610  gint page_nr,
611  gpointer user_data)
612 {
613  GtkPrintSettings *pSettings = gtk_print_operation_get_print_settings (operation);
614  gerbv_render_info_t renderInfo = {1.0, 1.0, 0, 0,
616  (gint) gtk_print_context_get_width (context),
617  (gint) gtk_print_context_get_height (context)};
618  cairo_t *cr;
619 
620  /* have to assume x and y resolutions are the same for now, since we
621  don't support differing scales in the gerb_render_info_t struct yet */
622  gdouble xres = gtk_print_context_get_dpi_x (context);
623  gdouble yres = gtk_print_context_get_dpi_y (context);
624  gdouble scalePercentage = gtk_print_settings_get_scale (pSettings);
625  renderInfo.scaleFactorX = scalePercentage / 100 * xres;
626  renderInfo.scaleFactorY = scalePercentage / 100 * yres;
627 
628  gerbv_render_translate_to_fit_display (mainProject, &renderInfo);
629  cr = gtk_print_context_get_cairo_context (context);
630  gerbv_render_all_layers_to_cairo_target_for_vector_output (mainProject, cr, &renderInfo);
631 }
632 
633 /* --------------------------------------------------------- */
634 void
635 callbacks_print_activate (GtkMenuItem *menuitem, gpointer user_data)
636 {
637  GtkPrintOperation *print;
638  /*GtkPrintOperationResult res;*/
639 
640  print = gtk_print_operation_new ();
641 
642  g_signal_connect (print, "begin_print", G_CALLBACK (callbacks_begin_print), NULL);
643  g_signal_connect (print, "draw_page", G_CALLBACK (callbacks_print_render_page), NULL);
644 
645  //GtkPrintSettings *pSettings = gtk_print_operation_get_print_settings (print);
646 
647  (void) gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
648  (GtkWindow *) screen.win.topLevelWindow , NULL);
649 
650  g_object_unref (print);
651 }
652 #endif /* GTK_CHECK_VERSION(2,10,0) */
653 
654 /* --------------------------------------------------------- */
655 void
656 callbacks_fullscreen_toggled (GtkMenuItem *menuitem, gpointer user_data)
657 {
658  //struct GtkWindow *win = (struct GtkWindow *)(screen.win.topLevelWindow);
659  GdkWindowState state = gdk_window_get_state (gtk_widget_get_window(screen.win.topLevelWindow));
660  if(state & GDK_WINDOW_STATE_FULLSCREEN)
661  gtk_window_unfullscreen (GTK_WINDOW(screen.win.topLevelWindow));
662  else
663  gtk_window_fullscreen (GTK_WINDOW(screen.win.topLevelWindow));
664 }
665 
666 /* --------------------------------------------------------- */
667 void
668 callbacks_show_toolbar_toggled (GtkMenuItem *menuitem, gpointer user_data)
669 {
670  gtk_widget_set_visible (user_data, GTK_CHECK_MENU_ITEM(menuitem)->active);
671 }
672 
673 /* --------------------------------------------------------- */
674 void
675 callbacks_show_sidepane_toggled (GtkMenuItem *menuitem, gpointer user_data)
676 {
677  gtk_widget_set_visible (user_data, GTK_CHECK_MENU_ITEM(menuitem)->active);
678 }
679 
680 /* --------------------------------------------------------- */
684 void
685 callbacks_toggle_layer_visibility_activate (GtkMenuItem *menuitem, gpointer user_data)
686 {
687  int i = GPOINTER_TO_INT(user_data);
688 
689  switch (i) {
690  case LAYER_SELECTED:
692  /* No break */
693  default:
694  if (0 <= i && i <= mainProject->last_loaded) {
696  } else {
697  /* Not in range */
698  return;
699  }
700  break;
701  case LAYER_ALL_ON:
702  for (i = 0; i <= mainProject->last_loaded; i++) {
703  mainProject->file[i]->isVisible = TRUE;
704  }
705  break;
706  case LAYER_ALL_OFF:
707  for (i = 0; i <= mainProject->last_loaded; i++) {
708  mainProject->file[i]->isVisible = FALSE;
709  }
710  break;
711  }
712 
713  /* Clear any selected items so they don't show after the layer is hidden */
714  render_clear_selection_buffer ();
715  callbacks_update_layer_tree ();
716 
717  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
718  render_refresh_rendered_image_on_screen ();
719  } else {
720  render_recreate_composite_surface (screen.drawing_area);
721  callbacks_force_expose_event_for_screen ();
722  }
723 }
724 
725 /* --------------------------------------------------------- */
726 void
727 callbacks_zoom_in_activate (GtkMenuItem *menuitem,
728  gpointer user_data)
729 {
730  render_zoom_display (ZOOM_IN, 0, 0, 0);
731 }
732 
733 /* --------------------------------------------------------- */
734 void
735 callbacks_zoom_out_activate (GtkMenuItem *menuitem,
736  gpointer user_data)
737 {
738  render_zoom_display (ZOOM_OUT, 0, 0, 0);
739 }
740 
741 /* --------------------------------------------------------- */
742 void
743 callbacks_fit_to_window_activate (GtkMenuItem *menuitem,
744  gpointer user_data)
745 {
746  gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
747  render_refresh_rendered_image_on_screen();
748 }
749 
750 /* --------------------------------------------------------- */
751 
752 static const char *error_type_string(gerbv_message_type_t type) {
753  switch (type) {
754  case GERBV_MESSAGE_FATAL:
755  return _("FATAL");
756  case GERBV_MESSAGE_ERROR:
757  return _("ERROR");
759  return _("Warning");
760  case GERBV_MESSAGE_NOTE:
761  return _("Note");
762  default:
763  return "Unknown";
764  }
765 }
766 
767 /* --------------------------------------------------------- */
774 void
776  gpointer user_data)
777 {
778  gerbv_aperture_list_t *aperture_list;
779  int i;
780 
781  /* Get a report of stats & errors accumulated from all layers */
782  gerbv_stats_t *stats_report = generate_gerber_analysis();
783 
784  /* General info report */
785  GString *general_report_str = g_string_new(NULL);
786  if (stats_report->layer_count == 0) {
787  g_string_printf(general_report_str,
788  _("No Gerber layers visible!"));
789  } else {
790  if (stats_report->error_list->error_text == NULL) {
791  g_string_printf(general_report_str,
792  ngettext("No errors found in %d visible "
793  "Gerber layer.",
794  "No errors found in %d visible "
795  "Gerber layers.",
796  stats_report->layer_count),
797  stats_report->layer_count);
798  } else {
799  g_string_printf(general_report_str,
800  ngettext("Found errors in %d visible "
801  "Gerber layer.",
802  "Found errors in %d visible "
803  "Gerber layers.",
804  stats_report->layer_count),
805  stats_report->layer_count);
806  }
807  }
808 
809  GtkWidget *general_label = gtk_label_new(general_report_str->str);
810  g_string_free(general_report_str, TRUE);
811  gtk_misc_set_alignment(GTK_MISC(general_label), 0, 0);
812  gtk_misc_set_padding(GTK_MISC(general_label), 7, 7);
813  gtk_label_set_selectable(GTK_LABEL(general_label), TRUE);
814 
815  struct table *general_table;
816 
817  if (stats_report->layer_count > 0 &&
818  stats_report->error_list->error_text != NULL) {
819  general_table = table_new_with_columns(3,
820  _("Layer"), G_TYPE_UINT, _("File"), G_TYPE_STRING,
821  _("Error"), G_TYPE_STRING);
822  } else {
823  general_table = table_new_with_columns(2,
824  _("Layer"), G_TYPE_UINT, _("File"), G_TYPE_STRING);
825  }
826  table_set_column_align(general_table, 0, 1.0);
827 
828  gerbv_fileinfo_t **files = mainProject->file;
829  gerbv_error_list_t *err_list;
830  for (i = 0; i <= mainProject->last_loaded; i++) {
831  if (files[i] && files[i]->isVisible &&
832  (files[i]->image->layertype ==
834  table_add_row(general_table, i + 1, files[i]->name, "");
835 
836  /* Check error report on layer */
837  if (stats_report->layer_count > 0 &&
838  stats_report->error_list->error_text != NULL) {
839  for (err_list = stats_report->error_list;
840  err_list != NULL;
841  err_list = err_list->next) {
842  if (i + 1 == err_list->layer) {
843  table_add_row(general_table,
844  err_list->layer,
845  error_type_string(
846  err_list->type),
847  err_list->error_text);
848  }
849  }
850  }
851  }
852  }
853 
854  /* G codes on active layers */
855  GtkWidget *G_report_window = gtk_scrolled_window_new(NULL, NULL);
856  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(G_report_window),
857  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
858 
859  struct table *G_table =
860  table_new_with_columns(3, _("Code"), G_TYPE_STRING,
861  _("Count"), G_TYPE_UINT, _("Note"), G_TYPE_STRING);
862  table_set_column_align(G_table, 0, 1.0);
863  table_set_column_align(G_table, 1, 1.0);
864  gtk_tree_view_set_headers_clickable(
865  GTK_TREE_VIEW(G_table->widget), TRUE);
866 
867  table_add_row(G_table, "G0", stats_report->G0,
868  _("Move"));
869  table_add_row(G_table, "G1", stats_report->G1,
870  _("1X linear interpolation"));
871  table_add_row(G_table, "G2", stats_report->G2,
872  _("CW interpolation"));
873  table_add_row(G_table, "G3", stats_report->G3,
874  _("CCW interpolation"));
875  table_add_row(G_table, "G4", stats_report->G4,
876  _("Comment/ignore block"));
877  table_add_row(G_table, "G10", stats_report->G10,
878  _("10X linear interpolation"));
879  table_add_row(G_table, "G11", stats_report->G11,
880  _("0.1X linear interpolation"));
881  table_add_row(G_table, "G12", stats_report->G12,
882  _("0.01X linear interpolation"));
883  table_add_row(G_table, "G36", stats_report->G36,
884  _("Poly fill on"));
885  table_add_row(G_table, "G37", stats_report->G37,
886  _("Poly fill off"));
887  table_add_row(G_table, "G54", stats_report->G54,
888  _("Tool prepare"));
889  table_add_row(G_table, "G55", stats_report->G55,
890  _("Flash prepare"));
891  table_add_row(G_table, "G70", stats_report->G70,
892  _("Units = inches"));
893  table_add_row(G_table, "G71", stats_report->G71,
894  _("Units = mm"));
895  table_add_row(G_table, "G74", stats_report->G74,
896  _("Disable 360 circ. interpolation"));
897  table_add_row(G_table, "G75", stats_report->G75,
898  _("Enable 360 circ. interpolation"));
899  table_add_row(G_table, "G90", stats_report->G90,
900  _("Absolute units"));
901  table_add_row(G_table, "G91", stats_report->G91,
902  _("Incremental units"));
903  table_add_row(G_table, "", stats_report->G_unknown,
904  _("Unknown G codes"));
905 
906  table_set_sortable(G_table);
907  gtk_container_add(GTK_CONTAINER(G_report_window), G_table->widget);
908 
909  /* D codes on active layers */
910  GtkWidget *D_report_window = gtk_scrolled_window_new(NULL, NULL);
911  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(D_report_window),
912  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
913 
914  struct table *D_table =
915  table_new_with_columns(3, _("Code"), G_TYPE_STRING,
916  _("Count"), G_TYPE_UINT, _("Note"), G_TYPE_STRING);
917  table_set_column_align(D_table, 0, 1.0);
918  table_set_column_align(D_table, 1, 1.0);
919  gtk_tree_view_set_headers_clickable(
920  GTK_TREE_VIEW(D_table->widget), TRUE);
921  table_add_row(D_table, "D1", stats_report->D1,
922  _("Exposure on"));
923  table_add_row(D_table, "D2", stats_report->D2,
924  _("Exposure off"));
925  table_add_row(D_table, "D3", stats_report->D3,
926  _("Flash aperture"));
927  table_add_row(D_table, "", stats_report->D_unknown,
928  _("Undefined D codes"));
929  table_add_row(D_table, "", stats_report->D_error,
930  _("D code Errors"));
931 
932  table_set_sortable(D_table);
933  gtk_container_add(GTK_CONTAINER(D_report_window), D_table->widget);
934 
935  /* M codes on active layers */
936  GtkWidget *M_report_window = gtk_scrolled_window_new(NULL, NULL);
937  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(M_report_window),
938  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
939 
940  struct table *M_table =
941  table_new_with_columns(3, _("Code"), G_TYPE_STRING,
942  _("Count"), G_TYPE_UINT, _("Note"), G_TYPE_STRING);
943  table_set_column_align(M_table, 0, 1.0);
944  table_set_column_align(M_table, 1, 1.0);
945  gtk_tree_view_set_headers_clickable(
946  GTK_TREE_VIEW(M_table->widget), TRUE);
947  table_add_row(M_table, "M0", stats_report->M0,
948  _("Program start"));
949  table_add_row(M_table, "M1", stats_report->M1,
950  _("Program stop"));
951  table_add_row(M_table, "M2", stats_report->M2,
952  _("Program end"));
953  table_add_row(M_table, "", stats_report->M_unknown,
954  _("Unknown M codes"));
955 
956  table_set_sortable(M_table);
957  gtk_container_add(GTK_CONTAINER(M_report_window), M_table->widget);
958 
959  /* Misc codes */
960  GtkWidget *misc_report_window = gtk_scrolled_window_new(NULL, NULL);
961  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(misc_report_window),
962  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
963 
964  struct table *misc_table =
965  table_new_with_columns(2, _("Code"), G_TYPE_STRING,
966  _("Count"), G_TYPE_UINT);
967  table_set_column_align(misc_table, 1, 1.0);
968  gtk_tree_view_set_headers_clickable(
969  GTK_TREE_VIEW(misc_table->widget), TRUE);
970  table_add_row(misc_table, "X", stats_report->X);
971  table_add_row(misc_table, "Y", stats_report->Y);
972  table_add_row(misc_table, "I", stats_report->I);
973  table_add_row(misc_table, "J", stats_report->J);
974  table_add_row(misc_table, "*", stats_report->star);
975  table_add_row(misc_table, _("Unknown"), stats_report->unknown);
976 
977  table_set_sortable(misc_table);
978  gtk_container_add(GTK_CONTAINER(misc_report_window),
979  misc_table->widget);
980 
981  /* Apertures definition in input files */
982  GtkWidget *aperture_def_report_window =
983  gtk_scrolled_window_new(NULL, NULL);
984  gtk_scrolled_window_set_policy(
985  GTK_SCROLLED_WINDOW(aperture_def_report_window),
986  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
987 
988  if (stats_report->aperture_list->number == -1) {
989  GtkWidget *aperture_def_label = gtk_label_new(
990  _("No aperture definitions found in active Gerber file(s)!"));
991  gtk_misc_set_alignment(GTK_MISC(aperture_def_label), 0, 0);
992  gtk_misc_set_padding(GTK_MISC(aperture_def_label), 7, 7);
993  gtk_label_set_selectable(GTK_LABEL(aperture_def_label), TRUE);
994  gtk_scrolled_window_add_with_viewport(
995  GTK_SCROLLED_WINDOW(aperture_def_report_window),
996  aperture_def_label);
997  } else {
998  struct table *aperture_def_table = table_new_with_columns(6,
999  _("Layer"), G_TYPE_UINT,
1000  _("D code"), G_TYPE_STRING,
1001  _("Aperture"), G_TYPE_STRING,
1002  _("Param[0]"), G_TYPE_DOUBLE,
1003  _("Param[1]"), G_TYPE_DOUBLE,
1004  _("Param[2]"), G_TYPE_DOUBLE);
1005  table_set_column_align(aperture_def_table, 0, 1.0);
1006  table_set_column_align(aperture_def_table, 1, 1.0);
1007  gtk_tree_view_set_headers_clickable(
1008  GTK_TREE_VIEW(aperture_def_table->widget), TRUE);
1009  gtk_tree_view_set_search_column(
1010  GTK_TREE_VIEW(aperture_def_table->widget), 1);
1011 
1012  GString *gstr = g_string_new(NULL);
1013  for (aperture_list = stats_report->aperture_list;
1014  aperture_list != NULL;
1015  aperture_list = aperture_list->next) {
1016  g_string_printf(gstr, "D%d", aperture_list->number);
1017  table_add_row(aperture_def_table,
1018  aperture_list->layer,
1019  gstr->str,
1020  aperture_names[aperture_list->type],
1021  aperture_list->parameter[0],
1022  aperture_list->parameter[1],
1023  aperture_list->parameter[2]);
1024  }
1025  g_string_free(gstr, TRUE);
1026  table_set_sortable(aperture_def_table);
1027  gtk_container_add(GTK_CONTAINER(aperture_def_report_window),
1028  aperture_def_table->widget);
1029  }
1030 
1031  /* Gerber aperture usage on active layers */
1032  GtkWidget *aperture_usage_report_window =
1033  gtk_scrolled_window_new(NULL, NULL);
1034  gtk_scrolled_window_set_policy(
1035  GTK_SCROLLED_WINDOW(aperture_usage_report_window),
1036  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1037 
1038  unsigned int aperture_count = 0;
1039 
1040  if (stats_report->D_code_list->number == -1) {
1041  GtkWidget *aperture_usage_label = gtk_label_new(
1042  _("No apertures used in Gerber file(s)!"));
1043  gtk_misc_set_alignment(GTK_MISC(aperture_usage_label), 0, 0);
1044  gtk_misc_set_padding(GTK_MISC(aperture_usage_label), 7, 7);
1045  gtk_label_set_selectable(GTK_LABEL(aperture_usage_label), TRUE);
1046  gtk_scrolled_window_add_with_viewport(
1047  GTK_SCROLLED_WINDOW(aperture_usage_report_window),
1048  aperture_usage_label);
1049  } else {
1050  struct table *aperture_usage_table = table_new_with_columns(2,
1051  _("Code"), G_TYPE_STRING,
1052  _("Count"), G_TYPE_UINT);
1053  table_set_column_align(aperture_usage_table, 0, 1.0);
1054  table_set_column_align(aperture_usage_table, 1, 1.0);
1055  gtk_tree_view_set_headers_clickable(
1056  GTK_TREE_VIEW(aperture_usage_table->widget), TRUE);
1057 
1058  GString *gstr = g_string_new(NULL);
1059  for (aperture_list = stats_report->D_code_list;
1060  aperture_list != NULL;
1061  aperture_list = aperture_list->next) {
1062  g_string_printf(gstr, "D%d", aperture_list->number);
1063  table_add_row(aperture_usage_table,
1064  gstr->str,
1065  aperture_list->count);
1066  aperture_count += aperture_list->count;
1067  }
1068  g_string_free(gstr, TRUE);
1069  table_add_row(aperture_usage_table, _("Total"), aperture_count);
1070  table_set_sortable(aperture_usage_table);
1071  gtk_container_add( GTK_CONTAINER(aperture_usage_report_window),
1072  aperture_usage_table->widget);
1073  }
1074 
1075  /* Create top level dialog window for report */
1076  GtkWidget *analyze_active_gerbers;
1077  analyze_active_gerbers = gtk_dialog_new_with_buttons(
1078  _("Gerber codes report on visible layers"),
1079  NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
1080  GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
1081  gtk_container_set_border_width(GTK_CONTAINER (analyze_active_gerbers), 5);
1082 
1083  gtk_dialog_set_default_response (GTK_DIALOG(analyze_active_gerbers),
1084  GTK_RESPONSE_ACCEPT);
1085  g_signal_connect (G_OBJECT(analyze_active_gerbers),
1086  "response",
1087  G_CALLBACK (gtk_widget_destroy),
1088  GTK_WIDGET(analyze_active_gerbers));
1089 
1090  /* Put general report text into scrolled window */
1091  GtkWidget *general_report_window =
1092  gtk_scrolled_window_new(NULL, NULL);
1093  gtk_scrolled_window_set_policy(
1094  GTK_SCROLLED_WINDOW(general_report_window),
1095  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1096 
1097  GtkWidget *vbox = gtk_vbox_new(0, 0);
1098  gtk_box_pack_start(GTK_BOX(vbox), general_label, 0, 0, 0);
1099  gtk_box_pack_start(GTK_BOX(vbox), general_table->widget, 0, 0, 0);
1100  gtk_scrolled_window_add_with_viewport(
1101  GTK_SCROLLED_WINDOW(general_report_window), vbox);
1102 
1103  /* Create tabbed notebook widget and add report widgets. */
1104  GtkWidget *notebook = gtk_notebook_new();
1105 
1106  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1107  GTK_WIDGET(general_report_window),
1108  gtk_label_new(_("General")));
1109 
1110  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1111  GTK_WIDGET(G_report_window),
1112  gtk_label_new(_("G codes")));
1113 
1114  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1115  GTK_WIDGET(D_report_window),
1116  gtk_label_new(_("D codes")));
1117 
1118  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1119  GTK_WIDGET(M_report_window),
1120  gtk_label_new(_("M codes")));
1121 
1122  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1123  GTK_WIDGET(misc_report_window),
1124  gtk_label_new(_("Misc. codes")));
1125 
1126  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1127  GTK_WIDGET(aperture_def_report_window),
1128  gtk_label_new(_("Aperture definitions")));
1129 
1130  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1131  GTK_WIDGET(aperture_usage_report_window),
1132  gtk_label_new(_("Aperture usage")));
1133 
1134  /* Now put notebook into dialog window and show the whole thing */
1135  gtk_container_add(
1136  GTK_CONTAINER(GTK_DIALOG(analyze_active_gerbers)->vbox),
1137  GTK_WIDGET(notebook));
1138  gtk_widget_set_size_request(analyze_active_gerbers, 640, 300);
1139  gtk_widget_show_all(analyze_active_gerbers);
1140 
1141  gerbv_stats_destroy(stats_report);
1142 }
1143 
1144 /* --------------------------------------------------------- */
1151 void
1153  gpointer user_data)
1154 {
1155  int i;
1156 
1157  gerbv_drill_stats_t *stats_report = generate_drill_analysis();
1158 
1159  /* General info report */
1160  GString *general_report_str = g_string_new(NULL);
1161  if (stats_report->layer_count == 0) {
1162  g_string_printf(general_report_str,
1163  _("No drill layers visible!"));
1164  } else {
1165  if (stats_report->error_list->error_text == NULL) {
1166  g_string_printf(general_report_str,
1167  ngettext("No errors found in %d visible "
1168  "drill layer.",
1169  "No errors found in %d visible "
1170  "drill layers.",
1171  stats_report->layer_count),
1172  stats_report->layer_count);
1173  } else {
1174  g_string_printf(general_report_str,
1175  ngettext("Found errors found in %d visible "
1176  "drill layer.",
1177  "Found errors found in %d visible "
1178  "drill layers.",
1179  stats_report->layer_count),
1180  stats_report->layer_count);
1181  }
1182  }
1183 
1184  GtkWidget *general_label = gtk_label_new(general_report_str->str);
1185  g_string_free(general_report_str, TRUE);
1186  gtk_misc_set_alignment(GTK_MISC(general_label), 0, 0);
1187  gtk_misc_set_padding(GTK_MISC(general_label), 7, 7);
1188  gtk_label_set_selectable(GTK_LABEL(general_label), TRUE);
1189 
1190  struct table *general_table;
1191 
1192  if (stats_report->layer_count > 0 &&
1193  stats_report->error_list->error_text != NULL) {
1194  general_table = table_new_with_columns(3,
1195  _("Layer"), G_TYPE_UINT, _("File"), G_TYPE_STRING,
1196  _("Error"), G_TYPE_STRING);
1197  } else {
1198  general_table = table_new_with_columns(2,
1199  _("Layer"), G_TYPE_UINT, _("File"), G_TYPE_STRING);
1200  }
1201  table_set_column_align(general_table, 0, 1.0);
1202 
1203  gerbv_error_list_t *err_list;
1204  gerbv_fileinfo_t **files = mainProject->file;
1205  for (i = 0; i <= mainProject->last_loaded; i++) {
1206  if (files[i] && files[i]->isVisible &&
1207  (files[i]->image->layertype ==
1209  table_add_row(general_table, i + 1, files[i]->name, "");
1210 
1211  /* Check error report on layer */
1212  if (stats_report->layer_count > 0 &&
1213  stats_report->error_list->error_text != NULL) {
1214  for (err_list = stats_report->error_list;
1215  err_list != NULL;
1216  err_list = err_list->next) {
1217  if (i + 1 != err_list->layer)
1218  continue;
1219  table_add_row(general_table,
1220  err_list->layer,
1221  error_type_string(err_list->type),
1222  err_list->error_text);
1223  }
1224  }
1225  }
1226  }
1227 
1228  /* G codes on active layers */
1229  GtkWidget *G_report_window = gtk_scrolled_window_new(NULL, NULL);
1230  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(G_report_window),
1231  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1232 
1233  struct table *G_table =
1234  table_new_with_columns(3, _("Code"), G_TYPE_STRING,
1235  _("Count"), G_TYPE_UINT, _("Note"), G_TYPE_STRING);
1236  table_set_column_align(G_table, 0, 1.0);
1237  table_set_column_align(G_table, 1, 1.0);
1238  gtk_tree_view_set_headers_clickable(
1239  GTK_TREE_VIEW(G_table->widget), TRUE);
1240 
1241  table_add_row(G_table, "G00", stats_report->G00,
1242  _("Rout mode"));
1243  table_add_row(G_table, "G01", stats_report->G01,
1244  _("1X linear interpolation"));
1245  table_add_row(G_table, "G02", stats_report->G02,
1246  _("CW interpolation"));
1247  table_add_row(G_table, "G03", stats_report->G03,
1248  _("CCW interpolation"));
1249  table_add_row(G_table, "G04", stats_report->G04,
1250  _("Variable dwell"));
1251  table_add_row(G_table, "G05", stats_report->G05,
1252  _("Drill mode"));
1253  table_add_row(G_table, "G85", stats_report->G85,
1254  _("Cut slot"));
1255  table_add_row(G_table, "G90", stats_report->G90,
1256  _("Absolute units"));
1257  table_add_row(G_table, "G91", stats_report->G91,
1258  _("Incremental units"));
1259  table_add_row(G_table, "G93", stats_report->G93,
1260  _("Zero set"));
1261  table_add_row(G_table, "", stats_report->G_unknown,
1262  _("Unknown G codes"));
1263 
1264  table_set_sortable(G_table);
1265  gtk_container_add(GTK_CONTAINER(G_report_window), G_table->widget);
1266 
1267  /* M codes on active layers */
1268  GtkWidget *M_report_window = gtk_scrolled_window_new(NULL, NULL);
1269  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(M_report_window),
1270  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1271 
1272  struct table *M_table =
1273  table_new_with_columns(3, _("Code"), G_TYPE_STRING,
1274  _("Count"), G_TYPE_UINT, _("Note"), G_TYPE_STRING);
1275  table_set_column_align(M_table, 0, 1.0);
1276  table_set_column_align(M_table, 1, 1.0);
1277  gtk_tree_view_set_headers_clickable(
1278  GTK_TREE_VIEW(M_table->widget), TRUE);
1279  table_add_row(M_table, "M00", stats_report->M00,
1280  _("End of program"));
1281  table_add_row(M_table, "M01", stats_report->M01,
1282  _("End of pattern"));
1283  table_add_row(M_table, "M18", stats_report->M18,
1284  _("Tool tip check"));
1285  table_add_row(M_table, "M25", stats_report->M25,
1286  _("Begin pattern"));
1287  table_add_row(M_table, "M30", stats_report->M30,
1288  _("End program rewind"));
1289  table_add_row(M_table, "M31", stats_report->M31,
1290  _("Begin pattern"));
1291  table_add_row(M_table, "M45", stats_report->M45,
1292  _("Long message"));
1293  table_add_row(M_table, "M47", stats_report->M47,
1294  _("Operator message"));
1295  table_add_row(M_table, "M48", stats_report->M48,
1296  _("Begin program header"));
1297  table_add_row(M_table, "M71", stats_report->M71,
1298  _("Metric units"));
1299  table_add_row(M_table, "M72", stats_report->M72,
1300  _("English units"));
1301  table_add_row(M_table, "M95", stats_report->M95,
1302  _("End program header"));
1303  table_add_row(M_table, "M97", stats_report->M97,
1304  _("Canned text"));
1305  table_add_row(M_table, "M98", stats_report->M98,
1306  _("Canned text"));
1307  table_add_row(M_table, "", stats_report->M_unknown,
1308  _("Unknown M codes"));
1309 
1310  table_set_sortable(M_table);
1311  gtk_container_add(GTK_CONTAINER(M_report_window), M_table->widget);
1312 
1313  /* Misc codes */
1314  GtkWidget *misc_report_window = gtk_scrolled_window_new(NULL, NULL);
1315  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(misc_report_window),
1316  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1317 
1318  struct table *misc_table =
1319  table_new_with_columns(2,
1320  /* Count is string for value hide. */
1321  _("Count"), G_TYPE_STRING,
1322  _("Code"), G_TYPE_STRING);
1323  table_set_column_align(misc_table, 0, 1.0);
1324  char *str = strdup("");
1325  sprintf(str, "%d", stats_report->comment);
1326  table_add_row(misc_table, str,_("Comments"));
1327  sprintf(str, "%d", stats_report->unknown);
1328  table_add_row(misc_table, str, _("Unknown codes"));
1329  sprintf(str, "%d", stats_report->R);
1330  table_add_row(misc_table, str, _("Repeat hole (R)"));
1331  free(str);
1332  if (stats_report->detect != NULL ) {
1333  table_add_row(misc_table, "", stats_report->detect);
1334  }
1335 
1336  table_set_sortable(misc_table);
1337  gtk_container_add(GTK_CONTAINER(misc_report_window),
1338  misc_table->widget);
1339 
1340  /* Drill usage on active layers */
1341  GtkWidget *drill_usage_report_window =
1342  gtk_scrolled_window_new(NULL, NULL);
1343  gtk_scrolled_window_set_policy(
1344  GTK_SCROLLED_WINDOW(drill_usage_report_window),
1345  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1346 
1347  struct table *drill_usage_table = table_new_with_columns(4,
1348  _("Drill no."), G_TYPE_UINT,
1349  _("Dia."), G_TYPE_DOUBLE,
1350  _("Units"), G_TYPE_STRING,
1351  _("Count"), G_TYPE_UINT);
1352 
1353  table_set_column_align(drill_usage_table, 0, 1.0);
1354  table_set_column_align(drill_usage_table, 3, 1.0);
1355  gtk_tree_view_set_headers_clickable(
1356  GTK_TREE_VIEW(drill_usage_table->widget), TRUE);
1357 
1359  for (drill_list = stats_report->drill_list;
1360  drill_list != NULL; drill_list = drill_list->next) {
1361  if (drill_list->drill_num == -1)
1362  break; /* No drill list */
1363 
1364  table_add_row(drill_usage_table,
1365  drill_list->drill_num,
1366  drill_list->drill_size,
1367  drill_list->drill_unit,
1368  drill_list->drill_count);
1369  }
1370 
1371  table_set_sortable(drill_usage_table);
1372  gtk_container_add(GTK_CONTAINER(drill_usage_report_window),
1373  drill_usage_table->widget);
1374 
1375  /* Create top level dialog window for report */
1376  GtkWidget *analyze_active_drill;
1377  analyze_active_drill = gtk_dialog_new_with_buttons(
1378  _("Drill codes report on visible layers"),
1379  NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
1380  GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
1381  gtk_container_set_border_width (GTK_CONTAINER (analyze_active_drill), 5);
1382 
1383  gtk_dialog_set_default_response (GTK_DIALOG(analyze_active_drill),
1384  GTK_RESPONSE_ACCEPT);
1385  g_signal_connect (G_OBJECT(analyze_active_drill),
1386  "response",
1387  G_CALLBACK (gtk_widget_destroy),
1388  GTK_WIDGET(analyze_active_drill));
1389 
1390  /* Put general report text into scrolled window */
1391  GtkWidget *general_report_window =
1392  gtk_scrolled_window_new(NULL, NULL);
1393  gtk_scrolled_window_set_policy(
1394  GTK_SCROLLED_WINDOW(general_report_window),
1395  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1396 
1397  GtkWidget *vbox = gtk_vbox_new(0, 0);
1398  gtk_box_pack_start(GTK_BOX(vbox), general_label, 0, 0, 0);
1399  gtk_box_pack_start(GTK_BOX(vbox), general_table->widget, 0, 0, 0);
1400  gtk_scrolled_window_add_with_viewport(
1401  GTK_SCROLLED_WINDOW(general_report_window), vbox);
1402 
1403  /* Create tabbed notebook widget and add report widgets. */
1404  GtkWidget *notebook = gtk_notebook_new();
1405 
1406  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1407  GTK_WIDGET(general_report_window),
1408  gtk_label_new(_("General")));
1409 
1410  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1411  GTK_WIDGET(G_report_window),
1412  gtk_label_new(_("G codes")));
1413 
1414  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1415  GTK_WIDGET(M_report_window),
1416  gtk_label_new(_("M codes")));
1417 
1418  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1419  GTK_WIDGET(misc_report_window),
1420  gtk_label_new(_("Misc. codes")));
1421 
1422  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1423  GTK_WIDGET(drill_usage_report_window),
1424  gtk_label_new(_("Drill usage")));
1425 
1426  /* Now put notebook into dialog window and show the whole thing */
1427  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(analyze_active_drill)->vbox),
1428  GTK_WIDGET(notebook));
1429  gtk_widget_set_size_request(analyze_active_drill, 400, 300);
1430  gtk_widget_show_all(analyze_active_drill);
1431 
1432  gerbv_drill_stats_destroy(stats_report);
1433 }
1434 
1435 /* --------------------------------------------------------- */
1436 void
1437 callbacks_control_gerber_options_activate (GtkMenuItem *menuitem,
1438  gpointer user_data)
1439 {
1440 
1441 }
1442 
1443 /* --------------------------------------------------------- */
1444 void
1445 callbacks_online_manual_activate (GtkMenuItem *menuitem,
1446  gpointer user_data)
1447 {
1448 
1449 }
1450 
1451 /* --------------------------------------------------------- */
1458 gboolean
1459 callbacks_quit_activate (GtkMenuItem *menuitem,
1460  gpointer user_data)
1461 {
1462  gboolean layers_dirty = FALSE;
1463  gint idx;
1464 
1465  for (idx = 0; idx<=mainProject->last_loaded; idx++) {
1466  if (mainProject->file[idx] == NULL) break;
1467  layers_dirty = layers_dirty || mainProject->file[idx]->layer_dirty;
1468  }
1469 
1470  if (layers_dirty &&
1472  _("Do you want to close all open layers and quit the program?"),
1473  _("Quitting the program will cause any unsaved changes to be lost."),
1474  FALSE,
1475  NULL)) {
1476  return TRUE; // stop propagation of the delete_event.
1477  // this would destroy the gui but not return from the gtk event loop.
1478  }
1479  gerbv_unload_all_layers (mainProject);
1480  gtk_main_quit();
1481  return FALSE; // more or less... meaningless :)
1482 }
1483 
1484 /* --------------------------------------------------------- */
1490 void
1491 callbacks_about_activate (GtkMenuItem *menuitem,
1492  gpointer user_data)
1493 {
1494  GtkWidget *aboutdialog1;
1495  /* TRANSLATORS: Replace this string with your names, one name per line. */
1496  gchar *translators = _("translator-credits");
1497 
1498  gchar *string = g_strdup_printf(_("gerbv -- a Gerber (RS-274/X) viewer.\n\n"
1499  "This is gerbv version %s\n"
1500  "Compiled on %s at %s\n"
1501  "\n"
1502  "gerbv is part of the gEDA Project.\n"
1503  "\n"
1504  "For more information see:\n"
1505  " gEDA homepage: http://geda-project.org/\n"
1506  " gEDA Wiki: http://wiki.geda-project.org/"),
1507  VERSION, __DATE__, __TIME__);
1508 #if GTK_CHECK_VERSION(2,6,0)
1509  gchar *license = g_strdup_printf(_("gerbv -- a Gerber (RS-274/X) viewer.\n\n"
1510  "Copyright (C) 2000-2007 Stefan Petersen\n\n"
1511  "This program is free software: you can redistribute it and/or modify\n"
1512  "it under the terms of the GNU General Public License as published by\n"
1513  "the Free Software Foundation, either version 2 of the License, or\n"
1514  "(at your option) any later version.\n\n"
1515  "This program is distributed in the hope that it will be useful,\n"
1516  "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1517  "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1518  "GNU General Public License for more details.\n\n"
1519  "You should have received a copy of the GNU General Public License\n"
1520  "along with this program. If not, see <http://www.gnu.org/licenses/>."));
1521  #include "authors.c"
1522  int a_size, i;
1523  gchar **a;
1524 
1525  aboutdialog1 = gtk_about_dialog_new ();
1526  gtk_container_set_border_width (GTK_CONTAINER (aboutdialog1), 5);
1527  gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (aboutdialog1), VERSION);
1528  gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (aboutdialog1), _("Gerbv"));
1529 
1530  gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG (aboutdialog1), translators);
1531  gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (aboutdialog1), string);
1532  gtk_about_dialog_set_license(GTK_ABOUT_DIALOG (aboutdialog1), license);
1533 
1534  /* The authors.c file is autogenerated at build time */
1535  a_size = sizeof(authors_string_array)/sizeof(authors_string_array[0]);
1536  a = g_new(gchar *, a_size);
1537  for (i = 0; i < a_size; i++)
1538  a[i] = _(authors_string_array[i]);
1539 
1540  gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG (aboutdialog1), (const gchar **)a);
1541  gtk_about_dialog_set_website(GTK_ABOUT_DIALOG (aboutdialog1), "http://gerbv.geda-project.org/");
1542  g_free(a);
1543 
1544  g_signal_connect (G_OBJECT(aboutdialog1),"response",
1545  G_CALLBACK (gtk_widget_destroy), GTK_WIDGET(aboutdialog1));
1546 
1547  g_free (string);
1548  g_free (license);
1549 #else
1550  aboutdialog1 = gtk_message_dialog_new ( GTK_WINDOW (screen.win.topLevelWindow),
1551  GTK_DIALOG_DESTROY_WITH_PARENT,
1552  GTK_MESSAGE_INFO,
1553  GTK_BUTTONS_CLOSE,
1554  string
1555  );
1556 
1557  gtk_window_set_title ( GTK_WINDOW (aboutdialog1), _("About Gerbv"));
1558 
1559  /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
1560  g_signal_connect_swapped (aboutdialog1, "response",
1561  G_CALLBACK (gtk_widget_destroy),
1562  aboutdialog1);
1563  g_free (string);
1564 #endif
1565 
1566  gtk_widget_show_all(GTK_WIDGET(aboutdialog1));
1567 
1568 }
1569 
1570 /* --------------------------------------------------------- */
1576 void
1577 callbacks_bugs_activate (GtkMenuItem *menuitem,
1578  gpointer user_data)
1579 {
1580  int i;
1581  #include "bugs.c"
1582 
1583  /* Create the top level dialog widget with an OK button */
1584  GtkWidget *bugs_dialog = gtk_dialog_new_with_buttons(_("Known bugs in gerbv"),
1585  NULL,
1586  GTK_DIALOG_DESTROY_WITH_PARENT,
1587  GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1588  NULL);
1589  gtk_container_set_border_width (GTK_CONTAINER (bugs_dialog), 5);
1590  gtk_dialog_set_default_response (GTK_DIALOG(bugs_dialog),
1591  GTK_RESPONSE_ACCEPT);
1592  g_signal_connect (G_OBJECT(bugs_dialog), "response",
1593  G_CALLBACK (gtk_widget_destroy), GTK_WIDGET(bugs_dialog));
1594 
1595  /* First create single bugs_string from bugs_string_array */
1596  GString *bugs_string = g_string_new(NULL);
1597  for (i=0; bugs_string_array[i] != NULL; i++) {
1598  /* gettext("") will return info string */
1599  g_string_append_printf(bugs_string, "%s\n",
1600  (bugs_string_array[i][0] == '\0') ? "" : _(bugs_string_array[i]));
1601  }
1602 
1603  /* Create GtkLabel to hold text */
1604  GtkWidget *bugs_label = gtk_label_new (bugs_string->str);
1605  g_string_free(bugs_string, FALSE);
1606  gtk_misc_set_alignment(GTK_MISC(bugs_label), 0, 0);
1607  gtk_misc_set_padding(GTK_MISC(bugs_label), 7, 7);
1608 
1609  /* Put text into scrolled window */
1610  GtkWidget *bugs_window = gtk_scrolled_window_new (NULL, NULL);
1611  gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(bugs_window),
1612  GTK_WIDGET(bugs_label));
1613  gtk_widget_set_size_request(bugs_window, 600, 300);
1614  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(bugs_dialog)->vbox),
1615  GTK_WIDGET(bugs_window));
1616 
1617  gtk_widget_show_all(GTK_WIDGET(bugs_dialog));
1618  gtk_dialog_run(GTK_DIALOG(bugs_dialog));
1619 
1620 }
1621 
1622 /* --------------------------------------------------------- */
1623 gdouble callbacks_calculate_actual_distance (gdouble inputDimension) {
1624  return screen_units(inputDimension);
1625 }
1626 
1627 /* --------------------------------------------------------- */
1628 void callbacks_update_ruler_pointers (void) {
1629  double xPosition, yPosition;
1630  xPosition = screenRenderInfo.lowerLeftX + (screen.last_x / screenRenderInfo.scaleFactorX);
1631  yPosition = screenRenderInfo.lowerLeftY + ((screenRenderInfo.displayHeight - screen.last_y) / screenRenderInfo.scaleFactorY);
1632 
1633  if (!((screen.unit == GERBV_MILS) && ((screenRenderInfo.scaleFactorX < 80)||(screenRenderInfo.scaleFactorY < 80)))) {
1634  xPosition = callbacks_calculate_actual_distance (xPosition);
1635  yPosition = callbacks_calculate_actual_distance (yPosition);
1636  }
1637  g_object_set (G_OBJECT (screen.win.hRuler), "position", xPosition, NULL);
1638  g_object_set (G_OBJECT (screen.win.vRuler), "position", yPosition, NULL);
1639 }
1640 
1641 /* --------------------------------------------------------- */
1642 static void
1643 callbacks_render_type_changed () {
1644  static gboolean isChanging = FALSE;
1645  if (isChanging)
1646  return;
1647 
1648  isChanging = TRUE;
1649  gerbv_render_types_t type = screenRenderInfo.renderType;
1650  GtkCheckMenuItem *check_item = screen.win.menu_view_render_group[type];
1651  dprintf ("%s(): type = %d, check_item = %p\n", __FUNCTION__, type, check_item);
1652  gtk_check_menu_item_set_active (check_item, TRUE);
1653  gtk_combo_box_set_active (screen.win.sidepaneRenderComboBox, type);
1654 
1655  render_refresh_rendered_image_on_screen();
1656  isChanging = FALSE;
1657 }
1658 
1659 /* --------------------------------------------------------- */
1660 static void
1661 callbacks_units_changed (gerbv_gui_unit_t unit) {
1662  static gboolean isChanging = FALSE;
1663 
1664  if (isChanging)
1665  return;
1666 
1667  isChanging = TRUE;
1668  screen.unit = unit;
1669 
1670  if (unit == GERBV_MILS){
1671  gtk_combo_box_set_active (GTK_COMBO_BOX (screen.win.statusUnitComboBox), GERBV_MILS);
1672  gtk_check_menu_item_set_active (screen.win.menu_view_unit_group[GERBV_MILS], TRUE);
1673  } else if (unit == GERBV_MMS){
1674  gtk_combo_box_set_active (GTK_COMBO_BOX (screen.win.statusUnitComboBox), GERBV_MMS);
1675  gtk_check_menu_item_set_active (screen.win.menu_view_unit_group[GERBV_MMS], TRUE);
1676  } else {
1677  gtk_combo_box_set_active (GTK_COMBO_BOX (screen.win.statusUnitComboBox), GERBV_INS);
1678  gtk_check_menu_item_set_active (screen.win.menu_view_unit_group[GERBV_INS], TRUE);
1679  }
1680 
1681  callbacks_update_ruler_scales ();
1682  callbacks_update_statusbar_coordinates (screen.last_x, screen.last_y);
1683 
1684  if (screen.tool == MEASURE)
1685  callbacks_update_statusbar_measured_distance (screen.win.lastMeasuredX, screen.win.lastMeasuredY);
1686 
1687  isChanging = FALSE;
1688 }
1689 
1690 /* --------------------------------------------------------- */
1691 static void
1692 callbacks_update_ruler_scales (void) {
1693  double xStart, xEnd, yStart, yEnd;
1694 
1695  xStart = screenRenderInfo.lowerLeftX;
1696  yStart = screenRenderInfo.lowerLeftY;
1697  xEnd = screenRenderInfo.lowerLeftX + (screenRenderInfo.displayWidth / screenRenderInfo.scaleFactorX);
1698  yEnd = screenRenderInfo.lowerLeftY + (screenRenderInfo.displayHeight / screenRenderInfo.scaleFactorY);
1699  /* mils can get super crowded with large boards, but inches are too
1700  large for most boards. So, we leave mils in for now and just switch
1701  to inches if the scale factor gets too small */
1702  if (!((screen.unit == GERBV_MILS) && ((screenRenderInfo.scaleFactorX < 80)||(screenRenderInfo.scaleFactorY < 80)))) {
1703  xStart = callbacks_calculate_actual_distance (xStart);
1704  xEnd = callbacks_calculate_actual_distance (xEnd);
1705  yStart = callbacks_calculate_actual_distance (yStart);
1706  yEnd = callbacks_calculate_actual_distance (yEnd);
1707  }
1708  /* make sure the widgets actually exist before setting (in case this gets
1709  called before everything is realized */
1710  if (screen.win.hRuler)
1711  gtk_ruler_set_range (GTK_RULER (screen.win.hRuler), xStart, xEnd, 0, xEnd - xStart);
1712  /* reverse y min and max, since the ruler starts at the top */
1713  if (screen.win.vRuler)
1714  gtk_ruler_set_range (GTK_RULER (screen.win.vRuler), yEnd, yStart, 0, yEnd - yStart);
1715 }
1716 
1717 /* --------------------------------------------------------- */
1718 void callbacks_update_scrollbar_limits (void){
1719  gerbv_render_info_t tempRenderInfo = {0, 0, 0, 0,
1721  screenRenderInfo.displayWidth,
1722  screenRenderInfo.displayHeight};
1723 
1724  GtkAdjustment *hAdjust = (GtkAdjustment *)screen.win.hAdjustment;
1725  GtkAdjustment *vAdjust = (GtkAdjustment *)screen.win.vAdjustment;
1726  gerbv_render_zoom_to_fit_display (mainProject, &tempRenderInfo);
1727  hAdjust->lower = tempRenderInfo.lowerLeftX;
1728  hAdjust->page_increment = hAdjust->page_size;
1729  hAdjust->step_increment = hAdjust->page_size / 10.0;
1730  vAdjust->lower = tempRenderInfo.lowerLeftY;
1731  vAdjust->page_increment = vAdjust->page_size;
1732  vAdjust->step_increment = vAdjust->page_size / 10.0;
1733  hAdjust->upper = tempRenderInfo.lowerLeftX + (tempRenderInfo.displayWidth / tempRenderInfo.scaleFactorX);
1734  hAdjust->page_size = screenRenderInfo.displayWidth / screenRenderInfo.scaleFactorX;
1735  vAdjust->upper = tempRenderInfo.lowerLeftY + (tempRenderInfo.displayHeight / tempRenderInfo.scaleFactorY);
1736  vAdjust->page_size = screenRenderInfo.displayHeight / screenRenderInfo.scaleFactorY;
1737  callbacks_update_scrollbar_positions ();
1738 }
1739 
1740 /* --------------------------------------------------------- */
1741 void callbacks_update_scrollbar_positions (void){
1742  gdouble positionX,positionY;
1743 
1744  positionX = screenRenderInfo.lowerLeftX;
1745  if (positionX < ((GtkAdjustment *)screen.win.hAdjustment)->lower)
1746  positionX = ((GtkAdjustment *)screen.win.hAdjustment)->lower;
1747  if (positionX > (((GtkAdjustment *)screen.win.hAdjustment)->upper - ((GtkAdjustment *)screen.win.hAdjustment)->page_size))
1748  positionX = (((GtkAdjustment *)screen.win.hAdjustment)->upper - ((GtkAdjustment *)screen.win.hAdjustment)->page_size);
1749  gtk_adjustment_set_value ((GtkAdjustment *)screen.win.hAdjustment, positionX);
1750 
1751  positionY = ((GtkAdjustment *)screen.win.vAdjustment)->upper - screenRenderInfo.lowerLeftY -
1752  ((GtkAdjustment *)screen.win.vAdjustment)->page_size +
1753  ((GtkAdjustment *)screen.win.vAdjustment)->lower;
1754  if (positionY < ((GtkAdjustment *)screen.win.vAdjustment)->lower)
1755  positionY = ((GtkAdjustment *)screen.win.vAdjustment)->lower;
1756  if (positionY > (((GtkAdjustment *)screen.win.vAdjustment)->upper - ((GtkAdjustment *)screen.win.vAdjustment)->page_size))
1757  positionY = (((GtkAdjustment *)screen.win.vAdjustment)->upper - ((GtkAdjustment *)screen.win.vAdjustment)->page_size);
1758  gtk_adjustment_set_value ((GtkAdjustment *)screen.win.vAdjustment, positionY);
1759 }
1760 
1761 /* --------------------------------------------------------- */
1762 gboolean
1763 callbacks_scrollbar_button_released (GtkWidget *widget, GdkEventButton *event){
1764  screen.off_x = 0;
1765  screen.off_y = 0;
1766  screen.state = NORMAL;
1767  render_refresh_rendered_image_on_screen();
1768  return FALSE;
1769 }
1770 
1771 /* --------------------------------------------------------- */
1772 gboolean
1773 callbacks_scrollbar_button_pressed (GtkWidget *widget, GdkEventButton *event){
1774  //screen.last_x = ((GtkAdjustment *)screen.win.hAdjustment)->value;
1775  screen.state = SCROLLBAR;
1776  return FALSE;
1777 }
1778 
1779 /* --------------------------------------------------------- */
1780 void callbacks_hadjustment_value_changed (GtkAdjustment *adjustment, gpointer user_data){
1781  /* make sure we're actually using the scrollbar to make sure we don't reset
1782  lowerLeftX during a scrollbar redraw during something else */
1783  if (screen.state == SCROLLBAR) {
1784  screenRenderInfo.lowerLeftX = gtk_adjustment_get_value (adjustment);
1785  }
1786 }
1787 
1788 /* --------------------------------------------------------- */
1789 void callbacks_vadjustment_value_changed (GtkAdjustment *adjustment, gpointer user_data){
1790  /* make sure we're actually using the scrollbar to make sure we don't reset
1791  lowerLeftY during a scrollbar redraw during something else */
1792  if (screen.state == SCROLLBAR) {
1793  screenRenderInfo.lowerLeftY = adjustment->upper -
1794  (gtk_adjustment_get_value (adjustment) + adjustment->page_size) + adjustment->lower;
1795  }
1796 }
1797 
1798 /* --------------------------------------------------------- */
1799 void
1800 callbacks_layer_tree_visibility_button_toggled (GtkCellRendererToggle *cell_renderer,
1801  gchar *path,
1802  gpointer user_data){
1803  GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
1804  ((GtkTreeView *) screen.win.layerTree);
1805  GtkTreeIter iter;
1806  gboolean newVisibility=TRUE;
1807  gint index;
1808 
1809  gtk_tree_model_get_iter_from_string ((GtkTreeModel *)list_store, &iter, path);
1810 
1811  GtkTreePath *treePath = gtk_tree_path_new_from_string (path);
1812  if (gtk_tree_model_get_iter((GtkTreeModel *)list_store, &iter, treePath)) {
1813  gint *indices;
1814 
1815  indices = gtk_tree_path_get_indices (treePath);
1816  index = indices[0];
1817  if (mainProject->file[index]->isVisible)
1818  newVisibility = FALSE;
1819  mainProject->file[index]->isVisible = newVisibility;
1820  /* clear any selected items so they don't show after the layer is hidden */
1821  render_clear_selection_buffer();
1822 
1823  callbacks_update_layer_tree ();
1824  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
1825  render_refresh_rendered_image_on_screen();
1826  }
1827  else {
1828  render_recreate_composite_surface (screen.drawing_area);
1829  callbacks_force_expose_event_for_screen ();
1830  }
1831  }
1832 }
1833 
1834 /* --------------------------------------------------------- */
1835 gint
1836 callbacks_get_col_number_from_tree_view_column (GtkTreeViewColumn *col)
1837 {
1838  GList *cols;
1839  gint num;
1840 
1841  g_return_val_if_fail ( col != NULL, -1 );
1842  g_return_val_if_fail ( col->tree_view != NULL, -1 );
1843  cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(col->tree_view));
1844  num = g_list_index(cols, (gpointer) col);
1845  g_list_free(cols);
1846  return num;
1847 }
1848 
1849 /* --------------------------------------------------------- */
1850 void
1851 callbacks_add_layer_button_clicked (GtkButton *button, gpointer user_data) {
1852  callbacks_open_layer_activate (NULL, NULL);
1853 }
1854 
1855 /* --------------------------------------------------------- */
1856 void
1857 callbacks_unselect_all_tool_buttons (void) {
1858 
1859 }
1860 
1861 void
1862 callbacks_switch_to_normal_tool_cursor (gint toolNumber) {
1863  GdkCursor *cursor;
1864 
1865  switch (toolNumber) {
1866  case POINTER:
1867  gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1868  GERBV_DEF_CURSOR);
1869  break;
1870  case PAN:
1871  cursor = gdk_cursor_new(GDK_FLEUR);
1872  gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1873  cursor);
1874  gdk_cursor_destroy(cursor);
1875  break;
1876  case ZOOM:
1877  cursor = gdk_cursor_new(GDK_SIZING);
1878  gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1879  cursor);
1880  gdk_cursor_destroy(cursor);
1881  break;
1882  case MEASURE:
1883  cursor = gdk_cursor_new(GDK_CROSSHAIR);
1884  gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1885  cursor);
1886  gdk_cursor_destroy(cursor);
1887  break;
1888  default:
1889  break;
1890  }
1891 }
1892 
1893 /* --------------------------------------------------------- */
1894 void
1895 callbacks_switch_to_correct_cursor (void) {
1896  GdkCursor *cursor;
1897 
1898  if (screen.state == IN_MOVE) {
1899  cursor = gdk_cursor_new(GDK_FLEUR);
1900  gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1901  cursor);
1902  gdk_cursor_destroy(cursor);
1903  return;
1904  }
1905  else if (screen.state == IN_ZOOM_OUTLINE) {
1906  cursor = gdk_cursor_new(GDK_SIZING);
1907  gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1908  cursor);
1909  gdk_cursor_destroy(cursor);
1910  return;
1911  }
1912  callbacks_switch_to_normal_tool_cursor (screen.tool);
1913 }
1914 
1915 /* --------------------------------------------------------- */
1916 void
1917 callbacks_change_tool (GtkButton *button, gpointer user_data) {
1918  gint toolNumber = GPOINTER_TO_INT (user_data);
1919 
1920  /* make sure se don't get caught in endless recursion here */
1921  if (screen.win.updatingTools)
1922  return;
1923  screen.win.updatingTools = TRUE;
1924  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPointer), FALSE);
1925  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPan), FALSE);
1926  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonZoom), FALSE);
1927  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonMeasure), FALSE);
1928  switch (toolNumber) {
1929  case POINTER:
1930  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPointer), TRUE);
1931  screen.tool = POINTER;
1932  screen.state = NORMAL;
1933  utf8_strncpy(screen.statusbar.diststr,
1934  _("Click to select objects in the current layer. Middle click and drag to pan."),
1935  MAX_DISTLEN);
1936  break;
1937  case PAN:
1938  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPan), TRUE);
1939  screen.tool = PAN;
1940  screen.state = NORMAL;
1941  utf8_strncpy(screen.statusbar.diststr,
1942  _("Click and drag to pan. Right click and drag to zoom."),
1943  MAX_DISTLEN);
1944  break;
1945  case ZOOM:
1946  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonZoom), TRUE);
1947  screen.tool = ZOOM;
1948  screen.state = NORMAL;
1949  utf8_strncpy(screen.statusbar.diststr,
1950  _("Click and drag to zoom in. Shift+click to zoom out."),
1951  MAX_DISTLEN);
1952  break;
1953  case MEASURE:
1954  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonMeasure), TRUE);
1955  screen.tool = MEASURE;
1956  screen.state = NORMAL;
1957  utf8_strncpy(screen.statusbar.diststr,
1958  _("Click and drag to measure a distance."),
1959  MAX_DISTLEN);
1960  break;
1961  default:
1962  break;
1963  }
1964  callbacks_switch_to_normal_tool_cursor (toolNumber);
1966  screen.win.updatingTools = FALSE;
1967  callbacks_force_expose_event_for_screen();
1968 }
1969 
1970 /* --------------------------------------------------------- */
1971 void
1972 callbacks_select_row (gint rowIndex) {
1973  GtkTreeSelection *selection;
1974  GtkTreeIter iter;
1975  GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
1976  ((GtkTreeView *) screen.win.layerTree);
1977 
1978  selection = gtk_tree_view_get_selection((GtkTreeView *) screen.win.layerTree);
1979  if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store), &iter, NULL, rowIndex)) {
1980  gtk_tree_selection_select_iter (selection, &iter);
1981  }
1982 }
1983 
1984 /* --------------------------------------------------------- */
1990 gint
1992  GtkTreeSelection *selection;
1993  GtkTreeIter iter;
1994  GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
1995  ((GtkTreeView *) screen.win.layerTree);
1996  gint index=-1,i=0;
1997 
1998  /* This will only work in single or browse selection mode! */
1999  selection = gtk_tree_view_get_selection((GtkTreeView *) screen.win.layerTree);
2000  if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
2001  while (gtk_tree_model_iter_nth_child ((GtkTreeModel *)list_store,
2002  &iter, NULL, i)){
2003  if (gtk_tree_selection_iter_is_selected (selection, &iter)) {
2004  return i;
2005  }
2006  i++;
2007  }
2008  }
2009  return index;
2010 }
2011 
2012 /* --------------------------------------------------------- */
2013 void
2014 callbacks_remove_layer_button_clicked (GtkButton *button, gpointer user_data) {
2015  gint index=callbacks_get_selected_row_index();
2016 
2017  if ((index >= 0) && (index <= mainProject->last_loaded)) {
2018  render_remove_selected_objects_belonging_to_layer (index);
2019  gerbv_unload_layer (mainProject, index);
2020  callbacks_update_layer_tree ();
2021  callbacks_select_row (0);
2022 
2023  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2024  render_refresh_rendered_image_on_screen();
2025  }
2026  else {
2027  render_recreate_composite_surface (screen.drawing_area);
2028  callbacks_force_expose_event_for_screen ();
2029  }
2030  }
2031 }
2032 
2033 /* --------------------------------------------------------- */
2034 void
2035 callbacks_move_layer_down_menu_activate (GtkMenuItem *menuitem, gpointer user_data) {
2036  callbacks_move_layer_down_button_clicked(NULL, NULL);
2037  gtk_widget_grab_focus (screen.win.layerTree);
2038 }
2039 
2040 /* --------------------------------------------------------- */
2041 void
2042 callbacks_move_layer_down_button_clicked (GtkButton *button, gpointer user_data) {
2043  gint index=callbacks_get_selected_row_index();
2044  if (index < 0) {
2045  show_no_layers_warning ();
2046  return;
2047  }
2048 
2049  if (index < mainProject->last_loaded) {
2050  gerbv_change_layer_order (mainProject, index, index + 1);
2051  callbacks_update_layer_tree ();
2052  callbacks_select_row (index + 1);
2053  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2054  render_refresh_rendered_image_on_screen ();
2055  }
2056  else {
2057  render_recreate_composite_surface (screen.drawing_area);
2058  callbacks_force_expose_event_for_screen ();
2059  }
2060  }
2061 }
2062 
2063 /* --------------------------------------------------------- */
2064 void
2065 callbacks_move_layer_up_menu_activate (GtkMenuItem *menuitem, gpointer user_data) {
2066  callbacks_move_layer_up_button_clicked (NULL, NULL);
2067  gtk_widget_grab_focus (screen.win.layerTree);
2068 }
2069 
2070 /* --------------------------------------------------------- */
2071 void
2072 callbacks_move_layer_up_button_clicked (GtkButton *button, gpointer user_data) {
2073  gint index=callbacks_get_selected_row_index();
2074  if (index < 0) {
2075  show_no_layers_warning ();
2076  return;
2077  }
2078  if (index > 0) {
2079  gerbv_change_layer_order (mainProject, index, index - 1);
2080  callbacks_update_layer_tree ();
2081  callbacks_select_row (index - 1);
2082  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2083  render_refresh_rendered_image_on_screen();
2084  }
2085  else {
2086  render_recreate_composite_surface (screen.drawing_area);
2087  callbacks_force_expose_event_for_screen ();
2088  }
2089  }
2090 }
2091 
2092 /* --------------------------------------------------------- */
2093 void callbacks_layer_tree_row_inserted (GtkTreeModel *tree_model, GtkTreePath *path,
2094  GtkTreeIter *oIter, gpointer user_data) {
2095  gint *indices=NULL,oldPosition,newPosition;
2096 
2097  if ((!screen.win.treeIsUpdating)&&(path != NULL)) {
2098  indices = gtk_tree_path_get_indices (path);
2099  if (indices) {
2100  newPosition = indices[0];
2101  oldPosition = callbacks_get_selected_row_index ();
2102  /* compensate for the fact that the old row has already
2103  been removed */
2104  if (oldPosition < newPosition)
2105  newPosition--;
2106  else
2107  oldPosition--;
2108  gerbv_change_layer_order (mainProject, oldPosition, newPosition);
2109 
2110  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2111  render_refresh_rendered_image_on_screen();
2112  }
2113  else {
2114  render_recreate_composite_surface (screen.drawing_area);
2115  callbacks_force_expose_event_for_screen ();
2116  }
2117  /* select the new line */
2118  GtkTreeSelection *selection;
2119  GtkTreeIter iter;
2120  GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2121  ((GtkTreeView *) screen.win.layerTree);
2122 
2123  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(screen.win.layerTree));
2124  if (gtk_tree_model_get_iter ((GtkTreeModel *)list_store, &iter, path))
2125  gtk_tree_selection_select_iter (selection, &iter);
2126  }
2127  }
2128 }
2129 
2130 /* --------------------------------------------------------- */
2131 void
2132 callbacks_show_color_picker_dialog (gint index){
2133  screen.win.colorSelectionDialog = NULL;
2134  GtkColorSelectionDialog *cs= (GtkColorSelectionDialog *) gtk_color_selection_dialog_new (_("Select a color"));
2135  GtkColorSelection *colorsel = (GtkColorSelection *) cs->colorsel;
2136 
2137  screen.win.colorSelectionDialog = (GtkWidget *) cs;
2138  screen.win.colorSelectionIndex = index;
2139  if (index >= 0)
2140  gtk_color_selection_set_current_color (colorsel, &mainProject->file[index]->color);
2141  else
2142  gtk_color_selection_set_current_color (colorsel, &mainProject->background);
2143  if ((screenRenderInfo.renderType >= GERBV_RENDER_TYPE_CAIRO_NORMAL)&&(index >= 0)) {
2144  gtk_color_selection_set_has_opacity_control (colorsel, TRUE);
2145  gtk_color_selection_set_current_alpha (colorsel, mainProject->file[index]->alpha);
2146  }
2147  gtk_widget_show_all((GtkWidget *)cs);
2148  if (gtk_dialog_run ((GtkDialog*)cs) == GTK_RESPONSE_OK) {
2149  GtkColorSelection *colorsel = (GtkColorSelection *) cs->colorsel;
2150  gint rowIndex = screen.win.colorSelectionIndex;
2151 
2152  if (index >= 0) {
2153  gtk_color_selection_get_current_color (colorsel, &mainProject->file[rowIndex]->color);
2154  gdk_colormap_alloc_color(gdk_colormap_get_system(), &mainProject->file[rowIndex]->color, FALSE, TRUE);
2155  }
2156  else {
2157  gtk_color_selection_get_current_color (colorsel, &mainProject->background);
2158  gdk_colormap_alloc_color(gdk_colormap_get_system(), &mainProject->background, FALSE, TRUE);
2159  }
2160  if ((screenRenderInfo.renderType >= GERBV_RENDER_TYPE_CAIRO_NORMAL)&&(index >= 0)) {
2161  mainProject->file[rowIndex]->alpha = gtk_color_selection_get_current_alpha (colorsel);
2162  }
2163 
2164  callbacks_update_layer_tree ();
2165  render_refresh_rendered_image_on_screen();
2166  }
2167  gtk_widget_destroy ((GtkWidget *)cs);
2168  screen.win.colorSelectionDialog = NULL;
2169 }
2170 
2171 /* --------------------------------------------------------- */
2172 void
2173 callbacks_invert_layer_clicked (GtkButton *button, gpointer user_data) {
2174  gint index=callbacks_get_selected_row_index();
2175  if (index < 0) {
2176  show_no_layers_warning ();
2177  return;
2178  }
2180  render_refresh_rendered_image_on_screen ();
2181  callbacks_update_layer_tree ();
2182 }
2183 
2184 /* --------------------------------------------------------- */
2185 void
2186 callbacks_change_layer_color_clicked (GtkButton *button, gpointer user_data) {
2187  gint index=callbacks_get_selected_row_index();
2188  if (index < 0) {
2189  show_no_layers_warning ();
2190  return;
2191  }
2192  callbacks_show_color_picker_dialog (index);
2193 }
2194 
2195 void
2196 callbacks_change_background_color_clicked (GtkButton *button, gpointer user_data) {
2197  callbacks_show_color_picker_dialog (-1);
2198 }
2199 
2200 /* --------------------------------------------------------------------------- */
2201 void
2202 callbacks_reload_layer_clicked (GtkButton *button, gpointer user_data) {
2203  gint index = callbacks_get_selected_row_index();
2204  if (index < 0) {
2205  show_no_layers_warning ();
2206  return;
2207  }
2208  render_remove_selected_objects_belonging_to_layer (index);
2209  gerbv_revert_file (mainProject, index);
2210  render_refresh_rendered_image_on_screen ();
2211  callbacks_update_layer_tree();
2212 }
2213 
2214 void
2215 callbacks_change_layer_edit_clicked (GtkButton *button, gpointer userData){
2216  gint index = callbacks_get_selected_row_index();
2217 
2218  if (index < 0) {
2219  show_no_layers_warning ();
2220  return;
2221  }
2222 
2223  interface_show_layer_edit_dialog(&mainProject->file[index]->transform,
2224  screen.unit);
2225  render_refresh_rendered_image_on_screen ();
2226  callbacks_update_layer_tree ();
2227 }
2228 
2229 /* --------------------------------------------------------------------------- */
2230 void
2231 callbacks_change_layer_format_clicked (GtkButton *button, gpointer user_data)
2232 {
2233  gerbv_HID_Attribute *attr = NULL;
2234  int n = 0;
2235  int i;
2236  gerbv_HID_Attr_Val * results = NULL;
2237  gint index = callbacks_get_selected_row_index();
2238  gchar *type;
2239  gint rc;
2240  if (index < 0) {
2241  show_no_layers_warning ();
2242  return;
2243  }
2244  dprintf ("%s(): index = %d\n", __FUNCTION__, index);
2245  attr = mainProject->file[index]->image->info->attr_list;
2246  n = mainProject->file[index]->image->info->n_attr;
2247  type = mainProject->file[index]->image->info->type;
2248  if (type == NULL)
2249  type = N_("Unknown type");
2250 
2251  if (attr == NULL || n == 0)
2252  {
2253  interface_show_alert_dialog(_("This file type does not currently have any editable features"),
2254  _("Format editing is currently only supported for Excellon drill file formats."),
2255  FALSE,
2256  NULL);
2257  return;
2258  }
2259 
2260  dprintf ("%s(): n = %d, attr = %p\n", __FUNCTION__, n, attr);
2261  if (n > 0)
2262  {
2263  if (mainProject->file[index]->layer_dirty) {
2264  rc = interface_get_alert_dialog_response (_("This layer has changed!"),
2265  _("Editing the file type will reload the layer, destroying your changes. Click OK to edit the file type and destroy your changes, or Cancel to leave."),
2266  TRUE,
2267  NULL);
2268  if (rc == 0) return; /* Return if user hit Cancel */
2269  }
2270 
2271  results = (gerbv_HID_Attr_Val *) malloc (n * sizeof (gerbv_HID_Attr_Val));
2272  if (results == NULL)
2273  {
2274  fprintf (stderr, "%s() -- malloc failed\n", __FUNCTION__);
2275  exit (1);
2276  }
2277 
2278  /* non-zero means cancel was picked */
2279  if (attribute_interface_dialog (attr, n, results,
2280  _("Edit file format"),
2281  _(type)))
2282  {
2283  return;
2284  }
2285 
2286  }
2287 
2288  dprintf (_("%s(): Reloading layer\n"), __FUNCTION__);
2289  gerbv_revert_file (mainProject, index);
2290 
2291  for (i = 0; i < n; i++)
2292  {
2293  if (results[i].str_value)
2294  free (results[i].str_value);
2295  }
2296 
2297  if (results)
2298  free (results);
2299  render_refresh_rendered_image_on_screen();
2300  callbacks_update_layer_tree();
2301 }
2302 
2303 /* --------------------------------------------------------------------------- */
2304 gboolean
2305 callbacks_layer_tree_key_press (GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
2306  /* if space is pressed while a color picker icon is in focus,
2307  show the color picker dialog. */
2308  if(event->keyval == GDK_space){
2309  GtkTreeView *tree;
2310  GtkTreePath *path;
2311  GtkTreeViewColumn *col;
2312  gint *indices;
2313  gint idx;
2314 
2315  tree = (GtkTreeView *) screen.win.layerTree;
2316  gtk_tree_view_get_cursor (tree, &path, &col);
2317  if (path) {
2318  indices = gtk_tree_path_get_indices (path);
2319  if (indices) {
2320  idx = callbacks_get_col_number_from_tree_view_column (col);
2321  if ((idx == 1) && (indices[0] <= mainProject->last_loaded)){
2322  callbacks_show_color_picker_dialog (indices[0]);
2323  }
2324  }
2325  gtk_tree_path_free (path);
2326  }
2327  }
2328  /* by default propagate the key press */
2329  return FALSE;
2330 }
2331 
2332 /* --------------------------------------------------------------------------- */
2333 gboolean
2334 callbacks_layer_tree_button_press (GtkWidget *widget, GdkEventButton *event,
2335  gpointer user_data) {
2336  GtkTreePath *path;
2337  GtkTreeIter iter;
2338  GtkTreeViewColumn *column;
2339  gint x,y;
2340  gint columnIndex;
2341 
2342  GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2343  ((GtkTreeView *) screen.win.layerTree);
2344  if (event->button == 1) {
2345  if (gtk_tree_view_get_path_at_pos ((GtkTreeView *) widget, event->x, event->y,
2346  &path, &column, &x, &y)) {
2347  if (gtk_tree_model_get_iter((GtkTreeModel *)list_store, &iter, path)) {
2348  gint *indices;
2349  indices = gtk_tree_path_get_indices (path);
2350  if (indices) {
2351  columnIndex = callbacks_get_col_number_from_tree_view_column (column);
2352  if ((columnIndex == 1) && (indices[0] <= mainProject->last_loaded)){
2353  callbacks_show_color_picker_dialog (indices[0]);
2354  /* don't propagate the signal, since drag and drop can
2355  sometimes activated during color selection */
2356  return TRUE;
2357  }
2358  }
2359  }
2360  }
2361  }
2362  /* don't pop up the menu if we don't have any loaded files */
2363  else if ((event->button == 3)&&(mainProject->last_loaded >= 0)) {
2364  gtk_menu_popup(GTK_MENU(screen.win.layerTreePopupMenu), NULL, NULL, NULL, NULL,
2365  event->button, event->time);
2366  }
2367  /* always allow the click to propagate and make sure the line is activated */
2368  return FALSE;
2369 }
2370 
2371 /* --------------------------------------------------------------------------- */
2372 void
2373 callbacks_update_layer_tree (void) {
2374  GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2375  ((GtkTreeView *) screen.win.layerTree);
2376  gint idx;
2377  GtkTreeIter iter;
2378  GtkTreeSelection *selection;
2379  gint oldSelectedRow;
2380 
2381  if (!screen.win.treeIsUpdating) {
2382  screen.win.treeIsUpdating = TRUE;
2383 
2384  oldSelectedRow = callbacks_get_selected_row_index();
2385  if (oldSelectedRow < 0)
2386  oldSelectedRow = 0;
2387  gtk_list_store_clear (list_store);
2388 
2389  for (idx = 0; idx <= mainProject->last_loaded; idx++) {
2390  if (mainProject->file[idx]) {
2391  GdkPixbuf *pixbuf,*blackPixbuf;
2392  guint32 color;
2393 
2394  unsigned char red, green, blue, alpha;
2395 
2396  red = (unsigned char) (mainProject->file[idx]->color.red * 255 / G_MAXUINT16) ;
2397  green = (unsigned char) (mainProject->file[idx]->color.green * 255 / G_MAXUINT16) ;
2398  blue = (unsigned char) (mainProject->file[idx]->color.blue *255 / G_MAXUINT16) ;
2399  alpha = (unsigned char) (mainProject->file[idx]->alpha * 255 / G_MAXUINT16) ;
2400 
2401  color = (red )* (256*256*256) + (green ) * (256*256) + (blue )* (256) + (alpha );
2402  pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 20, 15);
2403  gdk_pixbuf_fill (pixbuf, color);
2404 
2405  blackPixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 20, 15);
2406  color = (100 )* (256*256*256) + (100 ) * (256*256) + (100 )* (256) + (150 );
2407  gdk_pixbuf_fill (blackPixbuf, color);
2408 
2409  /* copy the color area into the black pixbuf */
2410  gdk_pixbuf_copy_area (pixbuf, 1, 1, 18, 13, blackPixbuf, 1, 1);
2411  /* free the color buffer, since we don't need it anymore */
2412  g_object_unref(pixbuf);
2413 
2414  gtk_list_store_append (list_store, &iter);
2415 
2416  gchar startChar[2],*modifiedCode;
2417  /* terminate the letter string */
2418  startChar[1] = 0;
2419 
2420  gint numberOfModifications = 0;
2421  if (mainProject->file[idx]->transform.inverted) {
2422  startChar[0] = 'I';
2423  numberOfModifications++;
2424  }
2425  if (mainProject->file[idx]->transform.mirrorAroundX ||
2427  startChar[0] = 'M';
2428  numberOfModifications++;
2429  }
2430  if ((fabs(mainProject->file[idx]->transform.translateX) > 0.000001) ||
2431  (fabs(mainProject->file[idx]->transform.translateY) > 0.000001)) {
2432  startChar[0] = 'T';
2433  numberOfModifications++;
2434  }
2435  if ((fabs(mainProject->file[idx]->transform.scaleX - 1) > 0.000001) ||
2436  (fabs(mainProject->file[idx]->transform.scaleY - 1) > 0.000001)) {
2437  startChar[0] = 'S';
2438  numberOfModifications++;
2439  }
2440  if ((fabs(mainProject->file[idx]->transform.rotation) > 0.000001)) {
2441  startChar[0] = 'R';
2442  numberOfModifications++;
2443  }
2444  if (numberOfModifications > 1)
2445  startChar[0] = '*';
2446  if (numberOfModifications == 0)
2447  modifiedCode = g_strdup ("");
2448  else
2449  modifiedCode = g_strdup (startChar);
2450 
2451  /* display any unsaved layers differently to show the user they are
2452  unsaved */
2453  gchar *layerName;
2454  if (mainProject->file[idx]->layer_dirty == TRUE) {
2455  /* The layer has unsaved changes in it. Show layer name in italics. */
2456  layerName = g_strconcat ("*","<i>",mainProject->file[idx]->name,"</i>",NULL);
2457  }
2458  else
2459  /* layer is clean. Show layer name using normal font. */
2460  layerName = g_strdup (mainProject->file[idx]->name);
2461 
2462  gtk_list_store_set (list_store, &iter,
2463  0, mainProject->file[idx]->isVisible,
2464  1, blackPixbuf,
2465  2, layerName,
2466  3, modifiedCode,
2467  -1);
2468  g_free (layerName);
2469  g_free (modifiedCode);
2470  /* pixbuf has a refcount of 2 now, as the list store has added its own reference */
2471  g_object_unref(blackPixbuf);
2472  }
2473  }
2474 
2475  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(screen.win.layerTree));
2476 
2477  /* if no line is selected yet, select the first row (if it has data) */
2478  /* or, select the line that was previously selected */
2479 
2480  if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
2481  if (gtk_tree_model_iter_nth_child ((GtkTreeModel *) list_store,
2482  &iter, NULL, oldSelectedRow)) {
2483  gtk_tree_selection_select_iter (selection, &iter);
2484  }
2485  }
2486  gboolean showItems = (mainProject->last_loaded >= 0);
2487  gtk_widget_set_sensitive (screen.win.curLayerMenuItem, showItems);
2488  gtk_widget_set_sensitive (screen.win.curAnalyzeMenuItem, showItems);
2489  gtk_widget_set_sensitive (screen.win.curEditMenuItem, showItems);
2490  gtk_widget_set_sensitive (screen.win.curFileMenuItem1, showItems);
2491  gtk_widget_set_sensitive (screen.win.curFileMenuItem2, showItems);
2492  gtk_widget_set_sensitive (screen.win.curFileMenuItem3, showItems);
2493  gtk_widget_set_sensitive (screen.win.curFileMenuItem4, showItems);
2494  gtk_widget_set_sensitive (screen.win.curFileMenuItem5, showItems);
2495  gtk_widget_set_sensitive (screen.win.curFileMenuItem6, showItems);
2496  gtk_widget_set_sensitive (screen.win.curFileMenuItem7, showItems);
2497  screen.win.treeIsUpdating = FALSE;
2498  }
2499 }
2500 
2501 /* --------------------------------------------------------------------------- */
2502 void
2503 callbacks_display_object_properties_clicked (GtkButton *button, gpointer user_data) {
2504  int i;
2505  gchar *layer_name;
2506  gchar *net_label;
2507  gboolean validAperture;
2508  double length = 0;
2509 
2510  gint index=callbacks_get_selected_row_index ();
2511  if (index < 0 || screen.selectionInfo.type == GERBV_SELECTION_EMPTY) {
2512  interface_show_alert_dialog(_("No object is currently selected"),
2513  _("Objects must be selected using the pointer tool before you can view the object properties."),
2514  FALSE,
2515  NULL);
2516  return;
2517  }
2518 
2519  for (i=0; i<screen.selectionInfo.selectedNodeArray->len; i++){
2520  gerbv_selection_item_t sItem = g_array_index (screen.selectionInfo.selectedNodeArray,
2521  gerbv_selection_item_t, i);
2522 
2523  gerbv_net_t *net = sItem.net;
2524  gerbv_image_t *image = sItem.image;
2525  gboolean show_length;
2526 
2527  /* get the aperture definition for the selected item */
2528  if (net->aperture > 0) {
2529  validAperture = TRUE;
2530  } else {
2531  validAperture = FALSE;
2532  }
2533 
2534  /* Also get layer name specified in file by %LN directive
2535  * (if it exists). */
2536  if (net->layer->name == NULL) {
2537  layer_name = g_strdup(_("<unnamed layer>"));
2538  } else {
2539  layer_name = g_strdup(net->layer->name);
2540  }
2541 
2542  if (net->label == NULL) {
2543  net_label = g_strdup(_("<unlabeled net>"));
2544  } else {
2545  net_label = g_strdup(net->label->str);
2546  }
2548  g_message (_("Object type: Polygon"));
2549  }
2550  else {
2551  switch (net->aperture_state){
2553  break;
2555  if (i != 0) g_message (" "); /* Spacing for a pretty display */
2556  show_length = 0;
2557  switch (net->interpolation) {
2562  g_message (_("Object type: Line"));
2563  length = line_length(net->start_x, net->start_y, net->stop_x, net->stop_y);
2564  show_length = 1;
2565  break;
2568  g_message (_("Object type: Arc"));
2569  if (net->cirseg->width == net->cirseg->height) {
2570  length = arc_length(net->cirseg->width,
2571  fabs(net->cirseg->angle1 - net->cirseg->angle2));
2572  show_length = 1;
2573  }
2574 
2575  break;
2576  default :
2577  g_message (_("Object type: Unknown"));
2578  break;
2579  }
2580  g_message (_(" Exposure: On"));
2581  if (validAperture) {
2582  aperture_report(image->aperture, net->aperture);
2583  }
2584  g_message (_(" Start location: (%g, %g)"),
2585  screen_units(net->start_x), screen_units(net->start_y));
2586  g_message (_(" Stop location: (%g, %g)"),
2587  screen_units(net->stop_x), screen_units(net->stop_y));
2588  if (show_length) {
2589  screen.length_sum += length;
2590  g_message (_(" Length: %g (sum: %g)"),
2591  screen_units(length), screen_units(screen.length_sum));
2592  }
2593  g_message (_(" Layer name: %s"), layer_name);
2594  g_message (_(" Net label: %s"), net_label);
2595  g_message (_(" In file: %s"), mainProject->file[index]->name);
2596  break;
2598  if (i != 0) g_message (" "); /* Spacing for a pretty display */
2599  g_message (_("Object type: Flashed aperture"));
2600  if (validAperture) {
2601  aperture_report(image->aperture, net->aperture);
2602  }
2603  g_message (_(" Location: (%g, %g)"),
2604  screen_units(net->stop_x), screen_units(net->stop_y));
2605  g_message (_(" Layer name: %s"), layer_name);
2606  g_message (_(" Net label: %s"), net_label);
2607  g_message (_(" In file: %s"), mainProject->file[index]->name);
2608  break;
2609  }
2610  }
2611  g_free (net_label);
2612  g_free (layer_name);
2613  }
2614  /* Use separator for different report requests */
2615  g_message ("---------------------------------------");
2616 }
2617 
2618 void
2619 callbacks_support_benchmark (gerbv_render_info_t *renderInfo) {
2620  int i;
2621  time_t start, now;
2622  GdkPixmap *renderedPixmap = gdk_pixmap_new (NULL, renderInfo->displayWidth,
2623  renderInfo->displayHeight, 24);
2624 
2625  // start by running the GDK (fast) rendering test
2626  i = 0;
2627  start = time(NULL);
2628  now = start;
2629  while( now - 30 < start) {
2630  i++;
2631  dprintf(_("Benchmark(): Starting redraw #%d\n"), i);
2632  gerbv_render_to_pixmap_using_gdk (mainProject, renderedPixmap, renderInfo, NULL, NULL);
2633  now = time(NULL);
2634  dprintf(_("Elapsed time = %ld seconds\n"), (long int) (now - start));
2635  }
2636  g_message(_("FAST (=GDK) mode benchmark: %d redraws in %ld seconds (%g redraws/second)\n"),
2637  i, (long int) (now - start), (double) i / (double)(now - start));
2638  gdk_pixmap_unref(renderedPixmap);
2639 
2640  // run the cairo (normal) render mode
2641  i = 0;
2642  start = time(NULL);
2643  now = start;
2645  while( now - 30 < start) {
2646  i++;
2647  dprintf(_("Benchmark(): Starting redraw #%d\n"), i);
2648  cairo_surface_t *cSurface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
2649  renderInfo->displayWidth, renderInfo->displayHeight);
2650  cairo_t *cairoTarget = cairo_create (cSurface);
2651  gerbv_render_all_layers_to_cairo_target (mainProject, cairoTarget, renderInfo);
2652  cairo_destroy (cairoTarget);
2653  cairo_surface_destroy (cSurface);
2654  now = time(NULL);
2655  dprintf(_("Elapsed time = %ld seconds\n"), (long int) (now - start));
2656  }
2657  g_message(_("NORMAL (=Cairo) mode benchmark: %d redraws in %ld seconds (%g redraws/second)\n"),
2658  i, (long int) (now - start), (double) i / (double)(now - start));
2659 }
2660 
2661 /* --------------------------------------------------------------------------- */
2662 void
2663 callbacks_benchmark_clicked (GtkButton *button, gpointer user_data)
2664 {
2665  // prepare render size and options (canvas size width and height are last 2 variables)
2666  gerbv_render_info_t renderInfo = {1.0, 1.0, 0, 0, GERBV_RENDER_TYPE_GDK, 640, 480};
2667  // autoscale the image for now...maybe we don't want to do this in order to
2668  // allow benchmarking of different zoom levels?
2670 
2671  g_message(_("Full zoom benchmarks\n"));
2672  callbacks_support_benchmark (&renderInfo);
2673 
2674 
2675  g_message(_("x5 zoom benchmarks\n"));
2676  renderInfo.lowerLeftX += (screenRenderInfo.displayWidth /
2677  screenRenderInfo.scaleFactorX) / 3.0;
2678  renderInfo.lowerLeftY += (screenRenderInfo.displayHeight /
2679  screenRenderInfo.scaleFactorY) / 3.0;
2680  renderInfo.scaleFactorX *= 5;
2681  renderInfo.scaleFactorY *= 5;
2682  callbacks_support_benchmark (&renderInfo);
2683 }
2684 
2685 /* --------------------------------------------------------------------------- */
2686 void
2687 callbacks_edit_object_properties_clicked (GtkButton *button, gpointer user_data){
2688 }
2689 
2690 /* --------------------------------------------------------------------------- */
2691 void
2692 callbacks_move_objects_clicked (GtkButton *button, gpointer user_data){
2693  /* for testing, just hard code in some translations here */
2694  gerbv_image_move_selected_objects (screen.selectionInfo.selectedNodeArray, -0.050, 0.050);
2695  callbacks_update_layer_tree();
2696  render_clear_selection_buffer ();
2697  render_refresh_rendered_image_on_screen ();
2698 }
2699 
2700 /* --------------------------------------------------------------------------- */
2701 void
2702 callbacks_reduce_object_area_clicked (GtkButton *button, gpointer user_data){
2703  /* for testing, just hard code in some parameters */
2704  gerbv_image_reduce_area_of_selected_objects (screen.selectionInfo.selectedNodeArray, 0.20, 3, 3, 0.01);
2705  render_clear_selection_buffer ();
2706  render_refresh_rendered_image_on_screen ();
2707 }
2708 
2709 /* --------------------------------------------------------------------------- */
2710 void
2711 callbacks_delete_objects_clicked (GtkButton *button, gpointer user_data){
2712  if (screen.selectionInfo.type == GERBV_SELECTION_EMPTY) {
2713  interface_show_alert_dialog(_("No object is currently selected"),
2714  _("Objects must be selected using the pointer tool before they can be deleted."),
2715  FALSE,
2716  NULL);
2717  return;
2718  }
2719 
2720  gint index=callbacks_get_selected_row_index();
2721  if (index < 0)
2722  return;
2723 
2724  if (mainProject->check_before_delete == TRUE) {
2726  _("Do you want to permanently delete the selected objects?"),
2727  _("Gerbv currently has no undo function, so this action cannot be undone. This action will not change the saved file unless you save the file afterwards."),
2728  TRUE,
2730  return;
2731  }
2732 
2733  gerbv_image_delete_selected_nets (mainProject->file[index]->image,
2734  screen.selectionInfo.selectedNodeArray);
2735  render_refresh_rendered_image_on_screen ();
2736  /* Set layer_dirty flag to TRUE */
2737  mainProject->file[index]->layer_dirty = TRUE;
2738  callbacks_update_layer_tree();
2739 
2740  render_clear_selection_buffer ();
2741  callbacks_update_selected_object_message(FALSE);
2742 }
2743 
2744 /* --------------------------------------------------------------------------- */
2745 gboolean
2746 callbacks_drawingarea_configure_event (GtkWidget *widget, GdkEventConfigure *event)
2747 {
2748  GdkDrawable *drawable = widget->window;
2749 
2750  gdk_drawable_get_size (drawable, &screenRenderInfo.displayWidth, &screenRenderInfo.displayHeight);
2751 
2752  /* set this up if cairo is compiled, since we may need to switch over to
2753  using the surface at any time */
2754  int x_off=0, y_off=0;
2755  GdkVisual *visual;
2756 
2757  if (GDK_IS_WINDOW(widget->window)) {
2758  /* query the window's backbuffer if it has one */
2759  GdkWindow *window = GDK_WINDOW(widget->window);
2760  gdk_window_get_internal_paint_info (window, &drawable, &x_off, &y_off);
2761  }
2762  visual = gdk_drawable_get_visual (drawable);
2763  if (screen.windowSurface)
2764  cairo_surface_destroy ((cairo_surface_t *)
2765  screen.windowSurface);
2766 
2767 #if defined(WIN32) || defined(QUARTZ)
2768  cairo_t *cairoTarget = gdk_cairo_create (GDK_WINDOW(widget->window));
2769 
2770  screen.windowSurface = cairo_get_target (cairoTarget);
2771  /* increase surface reference by one so it isn't freed when the cairo_t
2772  is destroyed next */
2773  screen.windowSurface = cairo_surface_reference (screen.windowSurface);
2774  cairo_destroy (cairoTarget);
2775 #else
2776  screen.windowSurface = (gpointer) cairo_xlib_surface_create (GDK_DRAWABLE_XDISPLAY (drawable),
2777  GDK_DRAWABLE_XID (drawable),
2778  GDK_VISUAL_XVISUAL (visual),
2779  screenRenderInfo.displayWidth,
2780  screenRenderInfo.displayHeight);
2781 #endif
2782  /* if this is the first time, go ahead and call autoscale even if we don't
2783  have a model loaded */
2784  if ((screenRenderInfo.scaleFactorX < 0.001)||(screenRenderInfo.scaleFactorY < 0.001)) {
2785  gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
2786  }
2787  render_refresh_rendered_image_on_screen();
2788  return TRUE;
2789 }
2790 
2791 /* --------------------------------------------------------- */
2792 gboolean
2793 callbacks_drawingarea_expose_event (GtkWidget *widget, GdkEventExpose *event)
2794 {
2795  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2796  GdkPixmap *new_pixmap;
2797  GdkGC *gc = gdk_gc_new(widget->window);
2798 
2799  /*
2800  * Create a pixmap with default background
2801  */
2802  new_pixmap = gdk_pixmap_new(widget->window,
2803  widget->allocation.width,
2804  widget->allocation.height,
2805  -1);
2806 
2807  gdk_gc_set_foreground(gc, &mainProject->background);
2808 
2809  gdk_draw_rectangle(new_pixmap, gc, TRUE,
2810  event->area.x, event->area.y,
2811  event->area.width, event->area.height);
2812 
2813  /*
2814  * Copy gerber pixmap onto background if we have one to copy.
2815  * Do translation at the same time.
2816  */
2817  if (screen.pixmap != NULL) {
2818  gdk_draw_pixmap(new_pixmap,
2819  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
2820  screen.pixmap,
2821  event->area.x - screen.off_x,
2822  event->area.y - screen.off_y,
2823  event->area.x, event->area.y,
2824  event->area.width, event->area.height);
2825  }
2826 
2827  /*
2828  * Draw the whole thing onto screen
2829  */
2830  gdk_draw_pixmap(widget->window,
2831  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
2832  new_pixmap,
2833  event->area.x, event->area.y,
2834  event->area.x, event->area.y,
2835  event->area.width, event->area.height);
2836 
2837  gdk_pixmap_unref(new_pixmap);
2838  gdk_gc_unref(gc);
2839 
2840  /*
2841  * Draw Zooming outline if we are in that mode
2842  */
2843  if (screen.state == IN_ZOOM_OUTLINE) {
2844  render_draw_zoom_outline(screen.centered_outline_zoom);
2845  }
2846  else if (screen.state == IN_MEASURE) {
2848  }
2849  if (screen.tool == MEASURE && screen.state != IN_MEASURE) {
2851  }
2852 
2853  return FALSE;
2854  }
2855 
2856  cairo_t *cr;
2857  int width, height;
2858  int x_off=0, y_off=0;
2859  GdkDrawable *drawable = widget->window;
2860  GdkVisual *visual;
2861 
2862  if (GDK_IS_WINDOW(widget->window)) {
2863  /* query the window's backbuffer if it has one */
2864  GdkWindow *window = GDK_WINDOW(widget->window);
2865  gdk_window_get_internal_paint_info (window,
2866  &drawable, &x_off, &y_off);
2867  }
2868  visual = gdk_drawable_get_visual (drawable);
2869  gdk_drawable_get_size (drawable, &width, &height);
2870 
2871 #if defined(WIN32) || defined(QUARTZ)
2872  /* FIXME */
2873  cr = gdk_cairo_create (GDK_WINDOW(widget->window));
2874 #else
2875  cairo_surface_t *buffert;
2876 
2877  buffert = (gpointer) cairo_xlib_surface_create (GDK_DRAWABLE_XDISPLAY (drawable),
2878  GDK_DRAWABLE_XID (drawable),
2879  GDK_VISUAL_XVISUAL (visual),
2880  event->area.width, event->area.height);
2881  cr = cairo_create (buffert);
2882 #endif
2883  cairo_translate (cr, -event->area.x + screen.off_x, -event->area.y + screen.off_y);
2884  render_project_to_cairo_target (cr);
2885  cairo_destroy (cr);
2886 #if !defined(WIN32) && !defined(QUARTZ)
2887  cairo_surface_destroy (buffert);
2888 #endif
2889 
2890  if (screen.tool == MEASURE)
2892  return FALSE;
2893 }
2894 
2895 /* Transforms screen coordinates to board ones */
2896 static void
2897 callbacks_screen2board(gdouble *X, gdouble *Y, gint x, gint y) {
2898 
2899  /* make sure we don't divide by zero (which is possible if the gui
2900  isn't displayed yet */
2901  if ((screenRenderInfo.scaleFactorX > 0.001)||(screenRenderInfo.scaleFactorY > 0.001)) {
2902  *X = screenRenderInfo.lowerLeftX + (x / screenRenderInfo.scaleFactorX);
2903  *Y = screenRenderInfo.lowerLeftY + ((screenRenderInfo.displayHeight - y)
2904  / screenRenderInfo.scaleFactorY);
2905  }
2906  else {
2907  *X = *Y = 0.0;
2908  }
2909 }
2910 
2911 /* --------------------------------------------------------- */
2912 static void
2913 callbacks_update_statusbar_coordinates (gint x, gint y) {
2914  gdouble X, Y;
2915 
2916  callbacks_screen2board(&X, &Y, x, y);
2917  if (screen.unit == GERBV_MILS) {
2918  utf8_snprintf(screen.statusbar.coordstr, MAX_COORDLEN,
2919  _("(%8.2f, %8.2f)"),
2920  COORD2MILS(X), COORD2MILS(Y));
2921  } else if (screen.unit == GERBV_MMS) {
2922  utf8_snprintf(screen.statusbar.coordstr, MAX_COORDLEN,
2923  _("(%8.3f, %8.3f)"),
2924  COORD2MMS(X), COORD2MMS(Y));
2925  } else {
2926  utf8_snprintf(screen.statusbar.coordstr, MAX_COORDLEN,
2927  _("(%4.5f, %4.5f)"),
2928  COORD2INS(X), COORD2INS(Y));
2929  }
2931 }
2932 
2933 void
2934 callbacks_update_selected_object_message (gboolean userTriedToSelect) {
2935  if (screen.tool != POINTER)
2936  return;
2937 
2938  gint selectionLength = screen.selectionInfo.selectedNodeArray->len;
2939  if ((selectionLength == 0)&&(userTriedToSelect)) {
2940  /* update status bar message to make sure the user knows
2941  about needing to select the layer */
2942  gchar *str = g_new(gchar, MAX_DISTLEN);
2943  utf8_strncpy(str, _("No object selected. Objects can only be selected in the active layer."),
2944  MAX_DISTLEN - 7);
2945  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN, "<b>%s</b>", str);
2946  g_free(str);
2947  }
2948  else if (selectionLength == 0) {
2949  utf8_strncpy(screen.statusbar.diststr,
2950  _("Click to select objects in the current layer. Middle click and drag to pan."),
2951  MAX_DISTLEN);
2952  }
2953  else if (selectionLength == 1) {
2954  utf8_strncpy(screen.statusbar.diststr,
2955  _("1 object is currently selected"),
2956  MAX_DISTLEN);
2957  }
2958  else {
2959  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2960  ngettext("%d object are currently selected",
2961  "%d objects are currently selected",
2962  selectionLength), selectionLength);
2963  }
2965 }
2966 
2967 /* --------------------------------------------------------- */
2968 gboolean
2969 callbacks_drawingarea_motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
2970 {
2971  int x, y;
2972  GdkModifierType state;
2973 
2974  if (event->is_hint)
2975  gdk_window_get_pointer (event->window, &x, &y, &state);
2976  else {
2977  x = event->x;
2978  y = event->y;
2979  state = event->state;
2980  }
2981 
2982  switch (screen.state) {
2983  case IN_MOVE: {
2984  if (screen.last_x != 0 || screen.last_y != 0) {
2985  /* Move pixmap to get a snappier feel of movement */
2986  screen.off_x += x - screen.last_x;
2987  screen.off_y += y - screen.last_y;
2988  }
2989  screenRenderInfo.lowerLeftX -= ((x - screen.last_x) / screenRenderInfo.scaleFactorX);
2990  screenRenderInfo.lowerLeftY += ((y - screen.last_y) / screenRenderInfo.scaleFactorY);
2991  callbacks_force_expose_event_for_screen ();
2992  callbacks_update_scrollbar_positions ();
2993  screen.last_x = x;
2994  screen.last_y = y;
2995  break;
2996  }
2997  case IN_ZOOM_OUTLINE: {
2998  if (screen.last_x || screen.last_y)
2999  render_draw_zoom_outline(screen.centered_outline_zoom);
3000  screen.last_x = x;
3001  screen.last_y = y;
3002  render_draw_zoom_outline(screen.centered_outline_zoom);
3003  break;
3004  }
3005  case IN_MEASURE: {
3006  /* clear the previous drawn line by drawing over it */
3008  callbacks_screen2board(&(screen.measure_last_x), &(screen.measure_last_y),
3009  x, y);
3010  /* screen.last_[xy] are updated to move the ruler pointers */
3011  screen.last_x = x;
3012  screen.last_y = y;
3013  /* draw the new line and write the new distance */
3015  break;
3016  }
3017  case IN_SELECTION_DRAG: {
3018  if (screen.last_x || screen.last_y)
3019  render_draw_selection_box_outline();
3020  screen.last_x = x;
3021  screen.last_y = y;
3022  render_draw_selection_box_outline();
3023  break;
3024  }
3025  default:
3026  screen.last_x = x;
3027  screen.last_y = y;
3028  break;
3029  }
3030  callbacks_update_statusbar_coordinates (x, y);
3031  callbacks_update_ruler_pointers ();
3032  return TRUE;
3033 } /* motion_notify_event */
3034 
3035 /* --------------------------------------------------------- */
3036 gboolean
3037 callbacks_drawingarea_button_press_event (GtkWidget *widget, GdkEventButton *event)
3038 {
3039  GdkCursor *cursor;
3040 
3041  switch (event->button) {
3042  case 1 :
3043  if (screen.tool == POINTER) {
3044  /* select */
3045  /* selection will only work with cairo, so do nothing if it's
3046  not compiled */
3047  screen.state = IN_SELECTION_DRAG;
3048  screen.start_x = event->x;
3049  screen.start_y = event->y;
3050  }
3051  else if (screen.tool == PAN) {
3052  /* Plain panning */
3053  screen.state = IN_MOVE;
3054  screen.last_x = event->x;
3055  screen.last_y = event->y;
3056  }
3057  else if (screen.tool == ZOOM) {
3058  screen.state = IN_ZOOM_OUTLINE;
3059  /* Zoom outline mode initiated */
3060  screen.start_x = event->x;
3061  screen.start_y = event->y;
3062  screen.centered_outline_zoom = event->state;
3063  }
3064  else if (screen.tool == MEASURE) {
3065  screen.state = IN_MEASURE;
3066  callbacks_screen2board(&(screen.measure_start_x), &(screen.measure_start_y),
3067  event->x, event->y);
3068  screen.measure_last_x = screen.measure_start_x;
3069  screen.measure_last_y = screen.measure_start_y;
3070  /* force an expose event to clear any previous measure lines */
3071  callbacks_force_expose_event_for_screen ();
3072  }
3073  break;
3074  case 2 :
3075  screen.state = IN_MOVE;
3076  screen.last_x = event->x;
3077  screen.last_y = event->y;
3078  cursor = gdk_cursor_new(GDK_FLEUR);
3079  gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
3080  cursor);
3081  gdk_cursor_destroy(cursor);
3082  break;
3083  case 3 :
3084  if (screen.tool == POINTER) {
3085  /* if no items are selected, try and find the item the user
3086  is pointing at */
3087  if (screen.selectionInfo.type == GERBV_SELECTION_EMPTY) {
3088  gint index=callbacks_get_selected_row_index();
3089  if ((index >= 0) &&
3090  (index <= mainProject->last_loaded) &&
3091  (mainProject->file[index]->isVisible)) {
3092  render_fill_selection_buffer_from_mouse_click(event->x,event->y,index,TRUE);
3093  } else {
3094  render_clear_selection_buffer ();
3095  render_refresh_rendered_image_on_screen ();
3096  }
3097  }
3098  /* only show the popup if we actually have something selected now */
3099  if (screen.selectionInfo.type != GERBV_SELECTION_EMPTY)
3100  gtk_menu_popup(GTK_MENU(screen.win.drawWindowPopupMenu), NULL, NULL, NULL, NULL,
3101  event->button, event->time);
3102  } else {
3103  /* Zoom outline mode initiated */
3104  screen.state = IN_ZOOM_OUTLINE;
3105  screen.start_x = event->x;
3106  screen.start_y = event->y;
3107  screen.centered_outline_zoom = event->state & GDK_SHIFT_MASK;
3108  cursor = gdk_cursor_new(GDK_SIZING);
3109  gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
3110  cursor);
3111  gdk_cursor_destroy(cursor);
3112  }
3113  break;
3114  case 4 : /* Scroll wheel */
3115  render_zoom_display (ZOOM_IN_CMOUSE, 0, event->x, event->y);
3116  break;
3117  case 5 : /* Scroll wheel */
3118  render_zoom_display (ZOOM_OUT_CMOUSE, 0, event->x, event->y);
3119  break;
3120  default:
3121  break;
3122  }
3123  callbacks_switch_to_correct_cursor ();
3124  return TRUE;
3125 }
3126 
3127 /* --------------------------------------------------------- */
3128 gboolean
3129 callbacks_drawingarea_button_release_event (GtkWidget *widget, GdkEventButton *event)
3130 {
3131  if (event->type == GDK_BUTTON_RELEASE) {
3132  if (screen.state == IN_MOVE) {
3133  screen.off_x = 0;
3134  screen.off_y = 0;
3135  render_refresh_rendered_image_on_screen();
3136  callbacks_switch_to_normal_tool_cursor (screen.tool);
3137  }
3138  else if (screen.state == IN_ZOOM_OUTLINE) {
3139  if ((event->state & GDK_SHIFT_MASK) != 0) {
3140  render_zoom_display (ZOOM_OUT_CMOUSE, 0, event->x, event->y);
3141  }
3142  /* if the user just clicks without dragging, then simply
3143  zoom in a preset amount */
3144  else if ((abs(screen.start_x - event->x) < 4) &&
3145  (abs(screen.start_y - event->y) < 4)) {
3146  render_zoom_display (ZOOM_IN_CMOUSE, 0, event->x, event->y);
3147  }
3148  else
3149  render_calculate_zoom_from_outline (widget, event);
3150  callbacks_switch_to_normal_tool_cursor (screen.tool);
3151  }
3152  else if (screen.state == IN_SELECTION_DRAG) {
3153  /* selection will only work with cairo, so do nothing if it's
3154  not compiled */
3155  gint index=callbacks_get_selected_row_index();
3156  /* determine if this was just a click or a box drag */
3157  if ((index >= 0) &&
3158  (mainProject->file[index]->isVisible)) {
3159  gboolean eraseOldSelection = TRUE;
3160 
3161  if ((event->state & GDK_SHIFT_MASK) ||
3162  (event->state & GDK_CONTROL_MASK)) {
3163  eraseOldSelection = FALSE;
3164  }
3165  if ((fabs((double)(screen.last_x - screen.start_x)) < 5) &&
3166  (fabs((double)(screen.last_y - screen.start_y)) < 5))
3167  render_fill_selection_buffer_from_mouse_click(event->x,event->y,index,eraseOldSelection);
3168  else
3169  render_fill_selection_buffer_from_mouse_drag(event->x,event->y,
3170  screen.start_x,screen.start_y,index,eraseOldSelection);
3171  /* check if anything was selected */
3172  callbacks_update_selected_object_message (TRUE);
3173  } else {
3174  render_clear_selection_buffer ();
3175  render_refresh_rendered_image_on_screen ();
3176  }
3177  }
3178  screen.last_x = screen.last_y = 0;
3179  screen.state = NORMAL;
3180  }
3181  return TRUE;
3182 } /* button_release_event */
3183 
3184 /* --------------------------------------------------------- */
3185 gboolean
3186 callbacks_window_key_press_event (GtkWidget *widget, GdkEventKey *event)
3187 {
3188  switch(event->keyval) {
3189  case GDK_Escape:
3190  if (screen.tool == POINTER) {
3191  utf8_strncpy(screen.statusbar.diststr,
3192  _("No objects are currently selected"),
3193  MAX_DISTLEN);
3195  render_clear_selection_buffer ();
3196  }
3197  break;
3198  default:
3199  break;
3200  }
3201 
3202  /* Escape may be used to abort outline zoom and just plain repaint */
3203  if (event->keyval == GDK_Escape) {
3204  screen.state = NORMAL;
3205  render_refresh_rendered_image_on_screen();
3206  }
3207 
3208  return TRUE;
3209 } /* key_press_event */
3210 
3211 /* --------------------------------------------------------- */
3212 gboolean
3213 callbacks_window_key_release_event (GtkWidget *widget, GdkEventKey *event)
3214 {
3215  return TRUE;
3216 } /* key_release_event */
3217 
3218 /* --------------------------------------------------------- */
3219 /* Scroll wheel */
3220 gboolean
3221 callbacks_window_scroll_event(GtkWidget *widget, GdkEventScroll *event)
3222 {
3223  switch (event->direction) {
3224  case GDK_SCROLL_UP:
3225  render_zoom_display (ZOOM_IN_CMOUSE, 0, event->x, event->y);
3226  break;
3227  case GDK_SCROLL_DOWN:
3228  render_zoom_display (ZOOM_OUT_CMOUSE, 0, event->x, event->y);
3229  break;
3230  case GDK_SCROLL_LEFT:
3231  /* Ignore */
3232  case GDK_SCROLL_RIGHT:
3233  /* Ignore */
3234  default:
3235  return TRUE;
3236  }
3237  return TRUE;
3238 } /* scroll_event */
3239 
3240 
3241 /* ------------------------------------------------------------------ */
3248 void
3250 {
3251  if ((screen.statusbar.coordstr != NULL)&&(GTK_IS_LABEL(screen.win.statusMessageLeft))) {
3252  gtk_label_set_text(GTK_LABEL(screen.win.statusMessageLeft), screen.statusbar.coordstr);
3253  }
3254  if ((screen.statusbar.diststr != NULL)&&(GTK_IS_LABEL(screen.win.statusMessageRight))) {
3255  gtk_label_set_markup(GTK_LABEL(screen.win.statusMessageRight), screen.statusbar.diststr);
3256  }
3257 }
3258 
3259 /* --------------------------------------------------------- */
3260 void
3261 callbacks_update_statusbar_measured_distance (gdouble dx, gdouble dy){
3262  gdouble delta = sqrt(dx*dx + dy*dy);
3263 
3264  if (screen.unit == GERBV_MILS) {
3265  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3266  _("Measured distance: %8.2f mils (%8.2f x, %8.2f y)"),
3267  COORD2MILS(delta), COORD2MILS(dx), COORD2MILS(dy));
3268  }
3269  else if (screen.unit == GERBV_MMS) {
3270  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3271  _("Measured distance: %8.3f mms (%8.3f x, %8.3f y)"),
3272  COORD2MMS(delta), COORD2MMS(dx), COORD2MMS(dy));
3273  }
3274  else {
3275  utf8_snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3276  _("Measured distance: %4.5f inches (%4.5f x, %4.5f y)"),
3277  COORD2INS(delta), COORD2INS(dx), COORD2INS(dy));
3278  }
3280 }
3281 
3282 /* --------------------------------------------------------- */
3283 void
3284 callbacks_sidepane_render_type_combo_box_changed (GtkComboBox *widget, gpointer user_data) {
3285  int type = gtk_combo_box_get_active (widget);
3286 
3287  dprintf ("%s(): type = %d\n", __FUNCTION__, type);
3288 
3289  if (type < 0 || type == screenRenderInfo.renderType)
3290  return;
3291 
3292  screenRenderInfo.renderType = type;
3293  callbacks_render_type_changed ();
3294 }
3295 
3296 /* --------------------------------------------------------- */
3297 void
3298 callbacks_viewmenu_rendertype_changed (GtkCheckMenuItem *widget, gpointer user_data) {
3299  gint type = GPOINTER_TO_INT(user_data);
3300 
3301  if (type == screenRenderInfo.renderType)
3302  return;
3303 
3304  dprintf ("%s(): type = %d\n", __FUNCTION__, type);
3305 
3306  screenRenderInfo.renderType = type;
3307  callbacks_render_type_changed ();
3308 }
3309 
3310 /* --------------------------------------------------------- */
3311 void
3312 callbacks_viewmenu_units_changed (GtkCheckMenuItem *widget, gpointer user_data) {
3313  gint unit = GPOINTER_TO_INT(user_data);
3314 
3315  if (unit < 0 || unit == screen.unit)
3316  return;
3317 
3318  dprintf ("%s(): unit = %d, screen.unit = %d\n", __FUNCTION__, unit, screen.unit);
3319 
3320  callbacks_units_changed (unit);
3321 }
3322 
3323 /* --------------------------------------------------------- */
3324 void
3325 callbacks_statusbar_unit_combo_box_changed (GtkComboBox *widget, gpointer user_data) {
3326  int unit = gtk_combo_box_get_active (widget);
3327 
3328  if (unit < 0 || unit == screen.unit)
3329  return;
3330 
3331  callbacks_units_changed (unit);
3332 }
3333 
3334 /* --------------------------------------------------------- */
3335 void
3336 callbacks_clear_messages_button_clicked (GtkButton *button, gpointer user_data) {
3337  GtkTextBuffer *textbuffer;
3338  GtkTextIter start, end;
3339 
3340  screen.length_sum = 0;
3341 
3342  textbuffer = gtk_text_view_get_buffer((GtkTextView*)screen.win.messageTextView);
3343  gtk_text_buffer_get_start_iter(textbuffer, &start);
3344  gtk_text_buffer_get_end_iter(textbuffer, &end);
3345  gtk_text_buffer_delete (textbuffer, &start, &end);
3346 }
3347 
3348 /* --------------------------------------------------------- */
3349 void
3350 callbacks_handle_log_messages(const gchar *log_domain, GLogLevelFlags log_level,
3351  const gchar *message, gpointer user_data)
3352 {
3353  GtkTextBuffer *textbuffer = NULL;
3354  GtkTextIter iter;
3355  GtkTextTag *tag;
3356  GtkTextMark *StartMark = NULL, *StopMark = NULL;
3357  GtkTextIter StartIter, StopIter;
3358  GtkWidget *dialog, *label;
3359 
3360  if (!screen.win.messageTextView)
3361  return;
3362 
3363  textbuffer = gtk_text_view_get_buffer((GtkTextView*)screen.win.messageTextView);
3364 
3365  /* create a mark for the end of the text. */
3366  gtk_text_buffer_get_end_iter(textbuffer, &iter);
3367 
3368  /* get the current end position of the text (it will be the
3369  start of the new text. */
3370  StartMark = gtk_text_buffer_create_mark(textbuffer,
3371  "NewTextStart", &iter, TRUE);
3372 
3373  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3374  "blue_foreground");
3375  /* the tag does not exist: create it and let them exist in the tag table.*/
3376  if (tag == NULL) {
3377  tag = gtk_text_buffer_create_tag(textbuffer, "black_foreground",
3378  "foreground", "black", NULL);
3379  tag = gtk_text_buffer_create_tag(textbuffer, "blue_foreground",
3380  "foreground", "blue", NULL);
3381  tag = gtk_text_buffer_create_tag(textbuffer, "red_foreground",
3382  "foreground", "red", NULL);
3383  tag = gtk_text_buffer_create_tag(textbuffer, "darkred_foreground",
3384  "foreground", "darkred", NULL);
3385  tag = gtk_text_buffer_create_tag(textbuffer, "darkblue_foreground",
3386  "foreground", "darkblue", NULL);
3387  tag = gtk_text_buffer_create_tag (textbuffer, "darkgreen_foreground",
3388  "foreground", "darkgreen", NULL);
3389  tag = gtk_text_buffer_create_tag (textbuffer,
3390  "saddlebrown_foreground",
3391  "foreground", "saddlebrown", NULL);
3392  }
3393 
3394  /*
3395  * See rgb.txt for the color names definition
3396  * (on my PC it is on /usr/X11R6/lib/X11/rgb.txt)
3397  */
3398  switch (log_level & G_LOG_LEVEL_MASK) {
3399  case G_LOG_LEVEL_ERROR:
3400  /* a message of this kind aborts the application calling abort() */
3401  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3402  "red_foreground");
3403  gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
3404  gtk_widget_show(screen.win.sidepane_notebook);
3405  break;
3406  case G_LOG_LEVEL_CRITICAL:
3407  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3408  "red_foreground");
3409  gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
3410  gtk_widget_show(screen.win.sidepane_notebook);
3411  break;
3412  case G_LOG_LEVEL_WARNING:
3413  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3414  "darkred_foreground");
3415  gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
3416  gtk_widget_show(screen.win.sidepane_notebook);
3417  break;
3418  case G_LOG_LEVEL_MESSAGE:
3419  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3420  "darkblue_foreground");
3421  gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
3422  gtk_widget_show(screen.win.sidepane_notebook);
3423  break;
3424  case G_LOG_LEVEL_INFO:
3425  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3426  "darkgreen_foreground");
3427  break;
3428  case G_LOG_LEVEL_DEBUG:
3429  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3430  "saddlebrown_foreground");
3431  break;
3432  default:
3433  tag = gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table(textbuffer),
3434  "black_foreground");
3435  break;
3436  }
3437 
3438  /*
3439  * Fatal aborts application. We will try to get the message out anyhow.
3440  */
3441  if (log_level & G_LOG_FLAG_FATAL) {
3442  fprintf(stderr, _("Fatal error: %s\n"), message);
3443 
3444  /* Try to show dialog box with error message */
3445  dialog = gtk_dialog_new_with_buttons(_("Fatal Error"),
3446  NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3447  GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
3448 
3449  label = gtk_label_new(g_strdup_printf(_("Fatal error: %s"), message));
3450  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),
3451  label);
3452  gtk_label_set_selectable(GTK_LABEL(label), TRUE);
3453  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),
3454  gtk_label_new(_("\nGerbv will be closed now!")));
3455 
3456  gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
3457 
3458  gtk_widget_show_all(dialog);
3459  gtk_dialog_run(GTK_DIALOG(dialog));
3460  }
3461 
3462  gtk_text_buffer_insert(textbuffer, &iter, message, -1);
3463  gtk_text_buffer_insert(textbuffer, &iter, "\n", -1);
3464 
3465  gtk_text_buffer_get_end_iter(textbuffer, &iter);
3466 
3467  StopMark = gtk_text_buffer_create_mark(textbuffer,
3468  "NewTextStop", &iter, TRUE);
3469 
3470  gtk_text_buffer_get_iter_at_mark(textbuffer, &StartIter, StartMark);
3471  gtk_text_buffer_get_iter_at_mark(textbuffer, &StopIter, StopMark);
3472 
3473  gtk_text_buffer_apply_tag(textbuffer, tag, &StartIter, &StopIter);
3474 }
3475 
3476 /* --------------------------------------------------------- */
3477 void callbacks_force_expose_event_for_screen (void){
3478 
3479  GdkRectangle update_rect;
3480 
3481  update_rect.x = 0;
3482  update_rect.y = 0;
3483  update_rect.width = screenRenderInfo.displayWidth;
3484  update_rect.height = screenRenderInfo.displayHeight;
3485 
3486  /* Calls expose_event */
3487  gdk_window_invalidate_rect (screen.drawing_area->window, &update_rect, FALSE);
3488 
3489  /* update other gui things that could have changed */
3490  callbacks_update_ruler_scales ();
3491  callbacks_update_scrollbar_limits ();
3492  callbacks_update_scrollbar_positions ();
3493 }
3494 
3495 static double screen_units(double d) {
3496  switch (screen.unit) {
3497  case GERBV_INS:
3498  return COORD2INS(d);
3499  break;
3500  case GERBV_MILS:
3501  return COORD2MILS(d);
3502  break;
3503  case GERBV_MMS:
3504  return COORD2MMS(d);
3505  break;
3506  }
3507 
3508  return d;
3509 }
3510 
3511 static double line_length(double x0, double y0, double x1, double y1) {
3512  double dx = x0 - x1;
3513  double dy = y0 - y1;
3514 
3515  return sqrt(dx*dx + dy*dy);
3516 }
3517 
3518 static double arc_length(double dia, double angle) {
3519  return M_PI*dia*(angle/360.0);
3520 }
3521 
3522 static void aperture_report(gerbv_aperture_t *apertures[], int aperture_num) {
3523  gerbv_aperture_type_t type = apertures[aperture_num]->type;
3524  double *params = apertures[aperture_num]->parameter;
3525 
3526  g_message (_(" Aperture used: D%d"), aperture_num);
3527  g_message (_(" Aperture type: %s"), aperture_names[type]);
3528 
3529  switch (type) {
3530  case GERBV_APTYPE_CIRCLE:
3531  g_message (_(" Diameter: %g"),
3532  screen_units(params[0]));
3533  break;
3535  case GERBV_APTYPE_OVAL:
3536  g_message (_(" Dimensions: %gx%g"),
3537  screen_units(params[0]),
3538  screen_units(params[1]));
3539  break;
3540  default:
3541  break;
3542  }
3543 }