patch from Canonical to allow better compilation with quartz
[geda-gerbv/spe.git] / src / callbacks.c
blob1874b2bc2648b52168546a93047b5ced81c1c568
1 /*
2 * gEDA - GNU Electronic Design Automation
3 * This file is a part of gerbv.
5 * Copyright (C) 2000-2003 Stefan Petersen (spe@stacken.kth.se)
7 * $Id$
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.
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.
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
24 /** \file callbacks.c
25 \brief Callback functions for the GUI widgets
26 \ingroup gerbv
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
33 #include <glib.h>
34 #include <gtk/gtk.h>
35 #include <gdk/gdk.h>
36 #if !defined(WIN32) && !defined(QUARTZ)
37 #include <gdk/gdkx.h>
38 #endif
39 #include <gdk/gdkkeysyms.h>
41 #ifdef HAVE_STDLIB_H
42 #include <stdlib.h>
43 #endif
45 #ifdef HAVE_STRING_H
46 #include <string.h>
47 #endif
49 #ifdef HAVE_TIME_H
50 #include <time.h>
51 #endif
53 #ifdef HAVE_UNISTD_H
54 #include <unistd.h>
55 #endif
57 #include <math.h>
58 #include "common.h"
59 #include "gerbv.h"
60 #include "main.h"
61 #include "callbacks.h"
62 #include "interface.h"
63 #include "attribute.h"
64 #include "render.h"
66 #include "draw-gdk.h"
68 #include "draw.h"
69 #ifdef WIN32
70 #include <cairo-win32.h>
71 #elif QUARTZ
72 #include <cairo-quartz.h>
73 #else
74 #include <cairo-xlib.h>
75 #endif
78 #define dprintf if(DEBUG) printf
80 /* This default extension should really not be changed, but if it absolutely
81 * must change, the ../win32/gerbv.nsi.in *must* be changed to reflect that.
82 * Just grep for the extension (gvp) and change it in two places in that file.
84 #define GERBV_PROJECT_FILE_NAME "Gerbv Project"
85 #define GERBV_PROJECT_FILE_EXT ".gvp"
86 #define GERBV_PROJECT_FILE_PAT "*.gvp"
88 #define SAVE_PROJECT 0
89 #define SAVE_AS_PROJECT 1
90 #define OPEN_PROJECT 2
91 # define _(String) (String)
93 /**Global variable to keep track of what's happening on the screen.
94 Declared extern in gerbv_screen.h
96 extern gerbv_screen_t screen;
97 extern gerbv_render_info_t screenRenderInfo;
100 /* These are the names of the valid apertures. These
101 * values are used in several places in this file.
102 * Please keep this in sync with the gerbv_aperture_type_t
103 * enum defined in gerbv.h */
104 char *ap_names[] = {"NONE",
105 "CIRCLE",
106 "RECTANGLE",
107 "OVAL", /* an ovular (obround) aperture */
108 "POLYGON", /* a polygon aperture */
109 "MACRO", /* a RS274X macro */
110 "MACRO_CIRCLE", /* a RS274X circle macro */
111 "MACRO_OUTLINE", /* a RS274X outline macro */
112 "MACRO_POLYGON", /* a RS274X polygon macro */
113 "MACRO_MOIRE", /* a RS274X moire macro */
114 "MACRO_THERMAL", /* a RS274X thermal macro */
115 "MACRO_LINE20", /* a RS274X line (code 20) macro */
116 "MACRO_LINE21", /* a RS274X line (code 21) macro */
117 "MACRO_LINE22" /* a RS274X line (code 22) macro */
120 static gint callbacks_get_selected_row_index (void);
121 static void callbacks_units_changed (gerbv_gui_unit_t unit);
122 static void callbacks_update_statusbar_coordinates (gint x, gint y);
123 static void callbacks_update_ruler_scales (void);
124 static void callbacks_render_type_changed (void);
125 static void show_no_layers_warning (void);
127 /* --------------------------------------------------------- */
129 static void show_no_layers_warning (void) {
130 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
131 "<b>No layers are currently loaded. A layer must be loaded first.</b>");
132 callbacks_update_statusbar();
135 /* --------------------------------------------------------- */
136 GtkWidget *
137 callbacks_generate_alert_dialog (gchar *primaryText, gchar *secondaryText){
138 GtkWidget *dialog, *label;
140 dialog = gtk_dialog_new_with_buttons (primaryText,
141 (GtkWindow *)screen.win.topLevelWindow,
142 GTK_DIALOG_DESTROY_WITH_PARENT,
143 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
144 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
145 NULL);
146 label = gtk_label_new (secondaryText);
147 /* Add the label, and show everything we've added to the dialog. */
148 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
149 label);
150 gtk_widget_show_all (dialog);
151 return dialog;
154 /* --------------------------------------------------------- */
156 * The file -> new menu item was selected. Create new
157 * project.
160 void
161 callbacks_new_activate (GtkMenuItem *menuitem, gpointer user_data)
163 if (mainProject->last_loaded >= 0) {
164 if (!interface_get_alert_dialog_response (
165 "Do you want to close any open layers and start a new project?",
166 "Starting a new project will cause all currently open layers to be closed. Any unsaved changes will be lost.",
167 FALSE,
168 NULL))
169 return;
171 /* Unload all layers and then clear layer window */
172 gerbv_unload_all_layers (mainProject);
173 callbacks_update_layer_tree ();
174 render_clear_selection_buffer ();
176 /* Destroy project info */
177 if (mainProject->project) {
178 g_free(mainProject->project);
179 mainProject->project = NULL;
181 render_refresh_rendered_image_on_screen();
185 /* --------------------------------------------------------- */
187 * The file -> open menu item was selected. Open a
188 * project file.
191 void
192 callbacks_open_project_activate (GtkMenuItem *menuitem,
193 gpointer user_data)
195 gchar *filename=NULL;
196 GtkFileFilter * filter;
198 if (mainProject->last_loaded >= 0) {
199 if (!interface_get_alert_dialog_response (
200 "Do you want to close any open layers and load an existing project?",
201 "Loading a project will cause all currently open layers to be closed. Any unsaved changes will be lost.",
202 FALSE,
203 NULL))
204 return;
207 screen.win.gerber =
208 gtk_file_chooser_dialog_new ("Open project file...",
209 NULL,
210 GTK_FILE_CHOOSER_ACTION_OPEN,
211 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
212 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
213 NULL);
214 gtk_file_chooser_set_current_folder ((GtkFileChooser *) screen.win.gerber,
215 mainProject->path);
217 filter = gtk_file_filter_new();
218 gtk_file_filter_set_name(filter, GERBV_PROJECT_FILE_NAME);
219 gtk_file_filter_add_pattern(filter, GERBV_PROJECT_FILE_PAT);
220 gtk_file_chooser_add_filter ((GtkFileChooser *) screen.win.gerber,
221 filter);
223 filter = gtk_file_filter_new();
224 gtk_file_filter_set_name(filter, "All");
225 gtk_file_filter_add_pattern(filter, "*");
226 gtk_file_chooser_add_filter ((GtkFileChooser *) screen.win.gerber,
227 filter);
229 gtk_widget_show (screen.win.gerber);
230 if (gtk_dialog_run ((GtkDialog*)screen.win.gerber) == GTK_RESPONSE_ACCEPT) {
231 filename =
232 gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (screen.win.gerber));
233 /* update the last folder */
234 g_free (mainProject->path);
235 mainProject->path = gtk_file_chooser_get_current_folder ((GtkFileChooser *) screen.win.gerber);
237 gtk_widget_destroy (screen.win.gerber);
239 if (filename) {
240 gerbv_unload_all_layers (mainProject);
241 main_open_project_from_filename (mainProject, filename);
243 gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
244 render_refresh_rendered_image_on_screen();
245 callbacks_update_layer_tree();
247 return;
251 /* --------------------------------------------------------- */
253 * The file -> open layer menu item was selected. Open a
254 * layer (or layers) from a file.
257 void
258 callbacks_open_layer_activate (GtkMenuItem *menuitem,
259 gpointer user_data)
261 GSList *filenames=NULL;
262 GSList *filename=NULL;
264 screen.win.gerber =
265 gtk_file_chooser_dialog_new ("Open Gerber, drill, or pick & place file(s)...",
266 NULL,
267 GTK_FILE_CHOOSER_ACTION_OPEN,
268 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
269 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
270 NULL);
272 gtk_file_chooser_set_select_multiple((GtkFileChooser *) screen.win.gerber, TRUE);
273 gtk_file_chooser_set_current_folder ((GtkFileChooser *) screen.win.gerber,
274 mainProject->path);
275 gtk_widget_show (screen.win.gerber);
276 if (gtk_dialog_run ((GtkDialog*)screen.win.gerber) == GTK_RESPONSE_ACCEPT) {
277 filenames =
278 gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER (screen.win.gerber));
279 /* update the last folder */
280 g_free (mainProject->path);
281 mainProject->path = gtk_file_chooser_get_current_folder ((GtkFileChooser *) screen.win.gerber);
283 gtk_widget_destroy (screen.win.gerber);
285 /* Now try to open all gerbers specified */
286 for (filename=filenames; filename; filename=filename->next) {
287 gerbv_open_layer_from_filename (mainProject, filename->data);
289 g_slist_free(filenames);
291 gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
292 render_refresh_rendered_image_on_screen();
293 callbacks_update_layer_tree();
295 return;
298 /* --------------------------------------------------------- */
299 void
300 callbacks_revert_activate (GtkMenuItem *menuitem,
301 gpointer user_data)
303 gerbv_revert_all_files (mainProject);
304 render_clear_selection_buffer();
305 callbacks_update_selected_object_message(FALSE);
306 render_refresh_rendered_image_on_screen();
307 callbacks_update_layer_tree();
310 /* --------------------------------------------------------- */
311 void
312 callbacks_save_project_activate (GtkMenuItem *menuitem,
313 gpointer user_data)
315 if (mainProject->project)
316 main_save_project_from_filename (mainProject, mainProject->project);
317 else
318 callbacks_generic_save_activate (menuitem, (gpointer) CALLBACKS_SAVE_PROJECT_AS);
319 callbacks_update_layer_tree();
320 return;
323 /* --------------------------------------------------------- */
324 void
325 callbacks_save_layer_activate (GtkMenuItem *menuitem,
326 gpointer user_data)
328 /* first figure out which layer in the layer side menu is selected */
329 gint index=callbacks_get_selected_row_index();
331 /* Now save that layer */
332 if (index >= 0) {
333 if (!gerbv_save_layer_from_index (mainProject, index, mainProject->file[index]->fullPathname)) {
334 interface_show_alert_dialog("Gerbv cannot export this file type",
335 NULL,
336 FALSE,
337 NULL);
338 mainProject->file[index]->layer_dirty = FALSE;
339 callbacks_update_layer_tree();
340 return;
343 callbacks_update_layer_tree();
344 return;
346 struct l_image_info {
347 gerbv_image_t *image;
348 gerbv_user_transformation_t *transform;
350 /* --------------------------------------------------------- */
351 /**Go through each file and look at visibility, then type.
352 Make sure we have at least 2 files.
355 gerbv_image_t *merge_images (int type)
357 gint i, filecount, img;
358 /* struct l_image_info *images; */
359 gerbv_image_t *out;
360 struct l_image_info {
361 gerbv_image_t *image;
362 gerbv_user_transformation_t *transform;
363 }*images;
366 images=(struct l_image_info *)g_new0(struct l_image_info,1);
367 out=NULL;
368 switch(type){
369 case CALLBACKS_SAVE_FILE_DRILLM:
370 type=GERBV_LAYERTYPE_DRILL;
371 break;
372 case CALLBACKS_SAVE_FILE_RS274XM:
373 type=GERBV_LAYERTYPE_RS274X;
374 break;
375 default:
376 GERB_MESSAGE("Unknown Layer type for merge\n");
377 goto err;
379 dprintf("Looking for matching files\n");
380 for (i=img=filecount=0;i<mainProject->max_files;++i){
381 if (mainProject->file[i] && mainProject->file[i]->isVisible &&
382 (mainProject->file[i]->image->layertype == type) ) {
383 ++filecount;
384 dprintf("Adding '%s'\n",mainProject->file[i]->name);
385 images[img].image=mainProject->file[i]->image;
386 /* printf("Adding transform\n"); */
387 images[img++].transform=&mainProject->file[i]->transform;
388 /* printf("Realloc\n"); */
389 images=(struct l_image_info *)g_renew(struct l_image_info, images,img+1);
391 /* printf("Done with add\n"); */
393 if(2>filecount){
394 GERB_MESSAGE ("Not Enough Files of same type to merge\n");
395 goto err;
397 dprintf("Now merging files\n");
398 for (i=0;i<img;++i){
399 gerbv_user_transformation_t *thisTransform;
400 gerbv_user_transformation_t identityTransform = {0,0,1,1,0,FALSE,FALSE,FALSE};
401 thisTransform=images[i].transform;
402 if (NULL == thisTransform )
403 thisTransform = &identityTransform;
404 if(0 == i)
405 out = gerbv_image_duplicate_image (images[i].image, thisTransform);
406 else
407 gerbv_image_copy_image(images[i].image,thisTransform,out);
409 err:
410 g_free(images);
411 return out;
413 /* --------------------------------------------------------- */
414 void
415 callbacks_generic_save_activate (GtkMenuItem *menuitem,
416 gpointer user_data)
418 gchar *filename=NULL;
419 gint processType = GPOINTER_TO_INT (user_data);
420 gchar *windowTitle=NULL;
421 GtkFileFilter * filter;
423 gint index=callbacks_get_selected_row_index ();
424 if (index < 0) {
425 interface_show_alert_dialog("No layer is currently selected",
426 "Please select a layer and try again.",
427 FALSE,
428 NULL);
429 return;
432 if (processType == CALLBACKS_SAVE_PROJECT_AS)
433 windowTitle = g_strdup ("Save project as...");
434 else if (processType == CALLBACKS_SAVE_FILE_PS)
435 windowTitle = g_strdup ("Export PS file as...");
436 else if (processType == CALLBACKS_SAVE_FILE_PDF)
437 windowTitle = g_strdup ("Export PDF file as...");
438 else if (processType == CALLBACKS_SAVE_FILE_SVG)
439 windowTitle = g_strdup ("Export SVG file as...");
440 else if (processType == CALLBACKS_SAVE_FILE_PNG)
441 windowTitle = g_strdup ("Export PNG file as...");
442 else if (processType == CALLBACKS_SAVE_FILE_RS274X)
443 windowTitle = g_strdup ("Export RS-274X file as...");
444 else if (processType == CALLBACKS_SAVE_FILE_DRILL)
445 windowTitle = g_strdup ("Export Excellon drill file as...");
446 else if (processType == CALLBACKS_SAVE_FILE_RS274XM)
447 windowTitle = g_strdup ("Export RS-274Xm file as...");
448 else if (processType == CALLBACKS_SAVE_FILE_DRILLM)
449 windowTitle = g_strdup ("Export Excellon drillm file as...");
450 else if (processType == CALLBACKS_SAVE_LAYER_AS)
451 windowTitle = g_strdup ("Save layer as...");
453 screen.win.gerber =
454 gtk_file_chooser_dialog_new (windowTitle, NULL,
455 GTK_FILE_CHOOSER_ACTION_SAVE,
456 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
457 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
458 NULL);
459 g_free (windowTitle);
461 /* if we're saving or exporting a layer, start off in the location of the
462 loaded file */
463 if (processType != CALLBACKS_SAVE_PROJECT_AS) {
464 gint index=callbacks_get_selected_row_index();
465 if (index >= 0) {
466 gchar *dirName = g_path_get_dirname (mainProject->file[index]->fullPathname);
467 gtk_file_chooser_set_current_folder ((GtkFileChooser *) screen.win.gerber,
468 dirName);
469 g_free (dirName);
473 if (processType == CALLBACKS_SAVE_PROJECT_AS) {
474 filter = gtk_file_filter_new();
475 gtk_file_filter_set_name(filter, GERBV_PROJECT_FILE_NAME);
476 gtk_file_filter_add_pattern(filter, GERBV_PROJECT_FILE_PAT);
477 gtk_file_chooser_add_filter ((GtkFileChooser *) screen.win.gerber,
478 filter);
480 filter = gtk_file_filter_new();
481 gtk_file_filter_set_name(filter, "All");
482 gtk_file_filter_add_pattern(filter, "*");
483 gtk_file_chooser_add_filter ((GtkFileChooser *) screen.win.gerber,
484 filter);
486 gtk_file_chooser_set_current_name ((GtkFileChooser *) screen.win.gerber,
487 "untitled" GERBV_PROJECT_FILE_EXT );
490 gtk_widget_show (screen.win.gerber);
491 if (gtk_dialog_run ((GtkDialog*)screen.win.gerber) == GTK_RESPONSE_ACCEPT) {
492 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (screen.win.gerber));
494 gtk_widget_destroy (screen.win.gerber);
496 if (filename) {
497 if (processType == CALLBACKS_SAVE_PROJECT_AS) {
498 main_save_as_project_from_filename (mainProject, filename);
499 rename_main_window(filename, NULL);
501 else if (processType == CALLBACKS_SAVE_FILE_PS)
502 gerbv_export_postscript_file_from_project_autoscaled (mainProject, filename);
503 else if (processType == CALLBACKS_SAVE_FILE_PDF)
504 gerbv_export_pdf_file_from_project_autoscaled (mainProject, filename);
505 else if (processType == CALLBACKS_SAVE_FILE_SVG)
506 gerbv_export_svg_file_from_project_autoscaled (mainProject, filename);
507 else if (processType == CALLBACKS_SAVE_FILE_PNG)
508 gerbv_export_png_file_from_project_autoscaled (mainProject,
509 screenRenderInfo.displayWidth, screenRenderInfo.displayHeight,
510 filename);
511 else if (processType == CALLBACKS_SAVE_LAYER_AS) {
512 gint index=callbacks_get_selected_row_index();
514 gerbv_save_layer_from_index (mainProject, index, filename);
515 /* rename the file path in the index, so future saves will reference the new file path */
516 g_free (mainProject->file[index]->fullPathname);
517 mainProject->file[index]->fullPathname = g_strdup (filename);
518 g_free (mainProject->file[index]->name);
519 mainProject->file[index]->name = g_path_get_basename (filename);
521 else if (processType == CALLBACKS_SAVE_FILE_RS274X) {
522 gint index=callbacks_get_selected_row_index();
524 gerbv_export_rs274x_file_from_image (filename, mainProject->file[index]->image,
525 &mainProject->file[index]->transform);
527 else if (processType == CALLBACKS_SAVE_FILE_DRILL) {
528 gint index=callbacks_get_selected_row_index();
530 gerbv_export_drill_file_from_image (filename, mainProject->file[index]->image,
531 &mainProject->file[index]->transform);
532 } /**create new image.... */
533 else if (processType == CALLBACKS_SAVE_FILE_RS274XM) {
534 gerbv_image_t *image;
535 gerbv_user_transformation_t t = {0,0,1,1,0,FALSE,FALSE,FALSE};
536 if(NULL != (image=merge_images(processType)) ){
537 /*printf("Preparing to export merge\n"); */
538 gerbv_export_rs274x_file_from_image (filename, image, &t);
539 gerbv_destroy_image(image);
540 GERB_MESSAGE ("Merged visible gerber layers and placed in '%s'\n",filename);
543 else if (processType == CALLBACKS_SAVE_FILE_DRILLM) {
544 gerbv_image_t *image;
545 gerbv_user_transformation_t t = {0,0,1,1,0,FALSE,FALSE,FALSE};
546 if(NULL != (image=merge_images(processType)) ){
547 gerbv_export_drill_file_from_image (filename, image,&t);
548 gerbv_destroy_image(image);
549 GERB_MESSAGE ("Merged visible drill layers and placed in '%s'\n",filename);
553 g_free (filename);
554 callbacks_update_layer_tree();
555 return;
558 /* --------------------------------------------------------- */
559 #if GTK_CHECK_VERSION(2,10,0)
561 static void
562 callbacks_begin_print (GtkPrintOperation *operation, GtkPrintContext *context,
563 gpointer user_data) {
564 gtk_print_operation_set_n_pages (operation, 1);
568 /* --------------------------------------------------------- */
569 static void
570 callbacks_print_render_page (GtkPrintOperation *operation,
571 GtkPrintContext *context,
572 gint page_nr,
573 gpointer user_data)
575 GtkPrintSettings *pSettings = gtk_print_operation_get_print_settings (operation);
576 gerbv_render_info_t renderInfo = {1.0, 1.0, 0, 0, 3,
577 (gint) gtk_print_context_get_width (context),
578 (gint) gtk_print_context_get_height (context)};
579 cairo_t *cr;
581 /* have to assume x and y resolutions are the same for now, since we
582 don't support differing scales in the gerb_render_info_t struct yet */
583 gdouble xres = gtk_print_context_get_dpi_x (context);
584 gdouble yres = gtk_print_context_get_dpi_y (context);
585 gdouble scalePercentage = gtk_print_settings_get_scale (pSettings);
586 renderInfo.scaleFactorX = scalePercentage / 100 * xres;
587 renderInfo.scaleFactorY = scalePercentage / 100 * yres;
589 gerbv_render_translate_to_fit_display (mainProject, &renderInfo);
590 cr = gtk_print_context_get_cairo_context (context);
591 gerbv_render_all_layers_to_cairo_target_for_vector_output (mainProject, cr, &renderInfo);
594 /* --------------------------------------------------------- */
595 void
596 callbacks_print_activate (GtkMenuItem *menuitem, gpointer user_data)
598 GtkPrintOperation *print;
599 GtkPrintOperationResult res;
601 print = gtk_print_operation_new ();
603 g_signal_connect (print, "begin_print", G_CALLBACK (callbacks_begin_print), NULL);
604 g_signal_connect (print, "draw_page", G_CALLBACK (callbacks_print_render_page), NULL);
606 //GtkPrintSettings *pSettings = gtk_print_operation_get_print_settings (print);
608 res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
609 (GtkWindow *) screen.win.topLevelWindow , NULL);
611 g_object_unref (print);
613 #endif /* GTK_CHECK_VERSION(2,10,0) */
615 /* --------------------------------------------------------- */
616 void
617 callbacks_fullscreen_toggled (GtkMenuItem *menuitem, gpointer user_data)
619 //struct GtkWindow *win = (struct GtkWindow *)(screen.win.topLevelWindow);
620 GdkWindowState state = gdk_window_get_state (gtk_widget_get_window(screen.win.topLevelWindow));
621 if(state & GDK_WINDOW_STATE_FULLSCREEN)
622 gtk_window_unfullscreen (GTK_WINDOW(screen.win.topLevelWindow));
623 else
624 gtk_window_fullscreen (GTK_WINDOW(screen.win.topLevelWindow));
627 /* --------------------------------------------------------- */
628 void
629 callbacks_show_toolbar_toggled (GtkMenuItem *menuitem, gpointer user_data)
631 gtk_widget_set_visible (user_data, GTK_CHECK_MENU_ITEM(menuitem)->active);
634 /* --------------------------------------------------------- */
635 void
636 callbacks_show_sidepane_toggled (GtkMenuItem *menuitem, gpointer user_data)
638 gtk_widget_set_visible (user_data, GTK_CHECK_MENU_ITEM(menuitem)->active);
641 /* --------------------------------------------------------- */
642 /** View/"Toggle visibility layer X" or Current layer/"Toggle visibility" menu item was activated.
643 * Set the isVisible flag on file X and update the treeview and rendering.
645 void
646 callbacks_toggle_layer_visibility_activate (GtkMenuItem *menuitem, gpointer user_data)
648 int i = GPOINTER_TO_INT(user_data);
649 if (i < 0)
650 i = callbacks_get_selected_row_index ();
652 if (0 <= i && i <= mainProject->last_loaded) {
653 mainProject->file[i]->isVisible = !mainProject->file[i]->isVisible;
654 /* clear any selected items so they don't show after the layer is hidden */
655 render_clear_selection_buffer();
657 callbacks_update_layer_tree ();
658 if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
659 render_refresh_rendered_image_on_screen();
661 else {
662 render_recreate_composite_surface (screen.drawing_area);
663 callbacks_force_expose_event_for_screen ();
668 /* --------------------------------------------------------- */
669 void
670 callbacks_zoom_in_activate (GtkMenuItem *menuitem,
671 gpointer user_data)
673 render_zoom_display (ZOOM_IN, 0, 0, 0);
676 /* --------------------------------------------------------- */
677 void
678 callbacks_zoom_out_activate (GtkMenuItem *menuitem,
679 gpointer user_data)
681 render_zoom_display (ZOOM_OUT, 0, 0, 0);
684 /* --------------------------------------------------------- */
685 void
686 callbacks_fit_to_window_activate (GtkMenuItem *menuitem,
687 gpointer user_data)
689 gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
690 render_refresh_rendered_image_on_screen();
694 /* --------------------------------------------------------- */
696 * The analyze -> analyze Gerbers menu item was selected.
697 * Compile statistics on all open Gerber layers and then display
698 * them.
701 void
702 callbacks_analyze_active_gerbers_activate(GtkMenuItem *menuitem,
703 gpointer user_data)
705 gerbv_stats_t *stats_report;
706 GString *G_report_string = g_string_new(NULL);
707 GString *D_report_string = g_string_new(NULL);
708 GString *M_report_string = g_string_new(NULL);
709 GString *misc_report_string = g_string_new(NULL);
710 GString *general_report_string = g_string_new(NULL);
711 GString *error_report_string = g_string_new(NULL);
712 gerbv_error_list_t *my_error_list;
713 gchar *error_level = NULL;
714 GString *aperture_def_report_string = g_string_new(NULL);
715 GString *aperture_use_report_string = g_string_new(NULL);
716 gerbv_aperture_list_t *my_aperture_list;
717 int idx;
718 int aperture_count = 0;
720 /* First get a report of stats & errors accumulated from all layers */
721 stats_report = generate_gerber_analysis();
723 /* General info report */
724 g_string_printf(general_report_string,
725 "General information\n");
726 g_string_append_printf(general_report_string,
727 " Active layer count = %d\n",
728 stats_report->layer_count);
729 g_string_append_printf(general_report_string,
730 "\n\n%-45s %-10s\n",
731 "Files processed",
732 "Layer number");
733 for (idx = 0; idx <= mainProject->last_loaded; idx++) {
734 if (mainProject->file[idx] &&
735 mainProject->file[idx]->isVisible &&
736 (mainProject->file[idx]->image->layertype == GERBV_LAYERTYPE_RS274X) ) {
737 g_string_append_printf(general_report_string,
738 " %-45s %-10d\n", mainProject->file[idx]->name, idx+1);
742 /* Error report (goes into general report tab) */
743 if (stats_report->layer_count == 0) {
744 g_string_printf(error_report_string,
745 "\n\nNo Gerber files active (visible)!\n");
746 } else if (stats_report->error_list->error_text == NULL) {
747 g_string_printf(error_report_string,
748 "\n\nNo errors found in active Gerber file(s)!\n");
749 } else {
750 g_string_printf(error_report_string,
751 "\n\nErrors found in active Gerber file(s):\n");
752 for(my_error_list = stats_report->error_list;
753 my_error_list != NULL;
754 my_error_list = my_error_list->next) {
755 switch(my_error_list->type) {
756 case GERBV_MESSAGE_FATAL: /* We should never get this one since the
757 * program should terminate first.... */
758 error_level = g_strdup_printf("FATAL: ");
759 break;
760 case GERBV_MESSAGE_ERROR:
761 error_level = g_strdup_printf("ERROR: ");
762 break;
763 case GERBV_MESSAGE_WARNING:
764 error_level = g_strdup_printf("WARNING: ");
765 break;
766 case GERBV_MESSAGE_NOTE:
767 error_level = g_strdup_printf("NOTE: ");
768 break;
770 g_string_append_printf(error_report_string,
771 " Layer %d: %s %s",
772 my_error_list->layer,
773 error_level,
774 my_error_list->error_text );
775 g_free(error_level);
780 g_string_append_printf(general_report_string,
781 "%s",
782 error_report_string->str);
783 g_string_free(error_report_string, TRUE);
785 /* Now compile stats related to reading G codes */
786 g_string_printf(G_report_string,
787 "G code statistics (all active layers)\n");
788 g_string_append_printf(G_report_string,
789 "<code> = <number of incidences>\n");
790 g_string_append_printf(G_report_string,
791 "G0 = %-6d (%s)\n",
792 stats_report->G0,
793 "Move");
794 g_string_append_printf(G_report_string,
795 "G1 = %-6d (%s)\n",
796 stats_report->G1,
797 "1X linear interpolation");
798 g_string_append_printf(G_report_string,
799 "G2 = %-6d (%s)\n",
800 stats_report->G2,
801 "CW interpolation");
802 g_string_append_printf(G_report_string,
803 "G3 = %-6d (%s)\n",
804 stats_report->G3,
805 "CCW interpolation");
806 g_string_append_printf(G_report_string,
807 "G4 = %-6d (%s)\n",
808 stats_report->G4,
809 "Comment/ignore block");
810 g_string_append_printf(G_report_string,
811 "G10 = %-6d (%s)\n",
812 stats_report->G10,
813 "10X linear interpolation");
814 g_string_append_printf(G_report_string,
815 "G11 = %-6d (%s)\n",
816 stats_report->G11,
817 "0.1X linear interpolation");
818 g_string_append_printf(G_report_string,
819 "G12 = %-6d (%s)\n",
820 stats_report->G12,
821 "0.01X linear interpolation");
822 g_string_append_printf(G_report_string,
823 "G36 = %-6d (%s)\n",
824 stats_report->G36,
825 "Poly fill on");
826 g_string_append_printf(G_report_string,
827 "G37 = %-6d (%s)\n",
828 stats_report->G37,
829 "Poly fill off");
830 g_string_append_printf(G_report_string,
831 "G54 = %-6d (%s)\n",
832 stats_report->G54,
833 "Tool prepare");
834 g_string_append_printf(G_report_string,
835 "G55 = %-6d (%s)\n",
836 stats_report->G55,
837 "Flash prepare");
838 g_string_append_printf(G_report_string,
839 "G70 = %-6d (%s)\n",
840 stats_report->G70,
841 "Units = inches");
842 g_string_append_printf(G_report_string,
843 "G71 = %-6d (%s)\n",
844 stats_report->G71,
845 "Units = mm");
846 g_string_append_printf(G_report_string,
847 "G74 = %-6d (%s)\n",
848 stats_report->G74,
849 "Disable 360 circ. interpolation");
850 g_string_append_printf(G_report_string,
851 "G75 = %-6d (%s)\n",
852 stats_report->G75,
853 "Enable 360 circ. interpolation");
854 g_string_append_printf(G_report_string,
855 "G90 = %-6d (%s)\n",
856 stats_report->G90,
857 "Absolute units");
858 g_string_append_printf(G_report_string,
859 "G91 = %-6d (%s)\n",
860 stats_report->G91,
861 "Incremental units");
862 g_string_append_printf(G_report_string,
863 "Unknown G codes = %d\n",
864 stats_report->G_unknown);
867 g_string_printf(D_report_string, "D code statistics (all active layers)\n");
868 g_string_append_printf(D_report_string,
869 "<code> = <number of incidences>\n");
870 g_string_append_printf(D_report_string,
871 "D1 = %-6d (%s)\n",
872 stats_report->D1,
873 "Exposure on");
874 g_string_append_printf(D_report_string,
875 "D2 = %-6d (%s)\n",
876 stats_report->D2,
877 "Exposure off");
878 g_string_append_printf(D_report_string,
879 "D3 = %-6d (%s)\n",
880 stats_report->D3,
881 "Flash aperture");
882 g_string_append_printf(D_report_string,
883 "Undefined D codes = %d\n",
884 stats_report->D_unknown);
885 g_string_append_printf(D_report_string,
886 "D code Errors = %d\n",
887 stats_report->D_error);
890 g_string_printf(M_report_string, "M code statistics (all active layers)\n");
891 g_string_append_printf(M_report_string,
892 "<code> = <number of incidences>\n");
893 g_string_append_printf(M_report_string,
894 "M0 = %-6d (%s)\n",
895 stats_report->M0,
896 "Program start");
897 g_string_append_printf(M_report_string,
898 "M1 = %-6d (%s)\n",
899 stats_report->M1,
900 "Program stop");
901 g_string_append_printf(M_report_string,
902 "M2 = %-6d (%s)\n",
903 stats_report->M2,
904 "Program end");
905 g_string_append_printf(M_report_string,
906 "Unknown M codes = %d\n",
907 stats_report->M_unknown);
910 g_string_printf(misc_report_string, "Misc code statistics (all active layers)\n");
911 g_string_append_printf(misc_report_string,
912 "<code> = <number of incidences>\n");
913 g_string_append_printf(misc_report_string,
914 "X = %d\n", stats_report->X);
915 g_string_append_printf(misc_report_string,
916 "Y = %d\n", stats_report->Y);
917 g_string_append_printf(misc_report_string,
918 "I = %d\n", stats_report->I);
919 g_string_append_printf(misc_report_string,
920 "J = %d\n", stats_report->J);
921 g_string_append_printf(misc_report_string,
922 "* = %d\n", stats_report->star);
923 g_string_append_printf(misc_report_string,
924 "Unknown codes = %d\n",
925 stats_report->unknown);
927 /* Report apertures defined in input files. */
929 if (stats_report->aperture_list->number == -1) {
930 g_string_printf(aperture_def_report_string,
931 "No aperture definitions found in Gerber file(s)!\n");
932 } else {
933 g_string_printf(aperture_def_report_string,
934 "Apertures defined in Gerber file(s) (by layer)\n");
935 g_string_append_printf(aperture_def_report_string,
936 " %-6s %-8s %12s %8s %8s %8s\n",
937 "Layer",
938 "D code",
939 "Aperture",
940 "Param[0]",
941 "Param[1]",
942 "Param[2]"
944 for(my_aperture_list = stats_report->aperture_list;
945 my_aperture_list != NULL;
946 my_aperture_list = my_aperture_list->next) {
948 g_string_append_printf(aperture_def_report_string,
949 " %-6d D%-4d%13s %8.3f %8.3f %8.3f\n",
950 my_aperture_list->layer,
951 my_aperture_list->number,
952 ap_names[my_aperture_list->type],
953 my_aperture_list->parameter[0],
954 my_aperture_list->parameter[1],
955 my_aperture_list->parameter[2]
960 /* Report apertures usage count in input files. */
961 if (stats_report->D_code_list->number == -1) {
962 g_string_printf(aperture_use_report_string,
963 "No apertures used in Gerber file(s)!\n");
964 } else {
966 /* Now add list of user-defined D codes (apertures) */
968 g_string_printf(aperture_use_report_string,
969 "Apertures used in Gerber file(s) (all active layers)\n");
970 g_string_append_printf(aperture_use_report_string,
971 "<aperture code> = <number of uses>\n");
972 for (my_aperture_list = stats_report->D_code_list;
973 my_aperture_list != NULL;
974 my_aperture_list = my_aperture_list->next) {
976 g_string_append_printf(aperture_use_report_string,
977 " D%d = %-6d\n",
978 my_aperture_list->number,
979 my_aperture_list->count
981 aperture_count += my_aperture_list->count;
984 g_string_append_printf(aperture_use_report_string,
985 "\nTotal number of aperture uses: %d\n", aperture_count);
988 /* Create top level dialog window for report */
989 GtkWidget *analyze_active_gerbers;
990 analyze_active_gerbers = gtk_dialog_new_with_buttons("Gerber codes report",
991 NULL,
992 GTK_DIALOG_DESTROY_WITH_PARENT,
993 GTK_STOCK_OK,
994 GTK_RESPONSE_ACCEPT,
995 NULL);
996 gtk_container_set_border_width (GTK_CONTAINER (analyze_active_gerbers), 5);
998 gtk_dialog_set_default_response (GTK_DIALOG(analyze_active_gerbers),
999 GTK_RESPONSE_ACCEPT);
1000 g_signal_connect (G_OBJECT(analyze_active_gerbers),
1001 "response",
1002 G_CALLBACK (gtk_widget_destroy),
1003 GTK_WIDGET(analyze_active_gerbers));
1005 /* Use fixed width font for all reports */
1006 PangoFontDescription *font =
1007 pango_font_description_from_string ("monospace");
1009 /* Create GtkLabel to hold general report text */
1010 GtkWidget *general_report_label = gtk_label_new (general_report_string->str);
1011 g_string_free (general_report_string, TRUE);
1012 gtk_misc_set_alignment(GTK_MISC(general_report_label), 0, 0);
1013 gtk_misc_set_padding(GTK_MISC(general_report_label), 13, 13);
1014 gtk_label_set_selectable(GTK_LABEL(general_report_label), TRUE);
1015 gtk_widget_modify_font (GTK_WIDGET(general_report_label),
1016 font);
1017 /* Put general report text into scrolled window */
1018 GtkWidget *general_code_report_window = gtk_scrolled_window_new (NULL, NULL);
1019 /* This throws a warning. Must find different approach.... */
1020 gtk_widget_set_size_request(GTK_WIDGET(general_code_report_window),
1021 200,
1022 300);
1023 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(general_code_report_window),
1024 GTK_WIDGET(general_report_label));
1026 /* Create GtkLabel to hold G code text */
1027 GtkWidget *G_report_label = gtk_label_new (G_report_string->str);
1028 g_string_free (G_report_string, TRUE);
1029 gtk_misc_set_alignment(GTK_MISC(G_report_label), 0, 0);
1030 gtk_misc_set_padding(GTK_MISC(G_report_label), 13, 13);
1031 gtk_label_set_selectable(GTK_LABEL(G_report_label), TRUE);
1032 gtk_widget_modify_font (GTK_WIDGET(G_report_label),
1033 font);
1035 /* Create GtkLabel to hold D code text */
1036 GtkWidget *D_report_label = gtk_label_new (D_report_string->str);
1037 g_string_free (D_report_string, TRUE);
1038 gtk_misc_set_alignment(GTK_MISC(D_report_label), 0, 0);
1039 gtk_misc_set_padding(GTK_MISC(D_report_label), 13, 13);
1040 gtk_label_set_selectable(GTK_LABEL(D_report_label), TRUE);
1041 gtk_widget_modify_font (GTK_WIDGET(D_report_label),
1042 font);
1044 /* Create GtkLabel to hold M code text */
1045 GtkWidget *M_report_label = gtk_label_new (M_report_string->str);
1046 g_string_free (M_report_string, TRUE);
1047 gtk_misc_set_alignment(GTK_MISC(M_report_label), 0, 0);
1048 gtk_misc_set_padding(GTK_MISC(M_report_label), 13, 13);
1049 gtk_label_set_selectable(GTK_LABEL(M_report_label), TRUE);
1050 gtk_widget_modify_font (GTK_WIDGET(M_report_label),
1051 font);
1053 /* Create GtkLabel to hold misc code text */
1054 GtkWidget *misc_report_label = gtk_label_new (misc_report_string->str);
1055 g_string_free (misc_report_string, TRUE);
1056 gtk_misc_set_alignment(GTK_MISC(misc_report_label), 0, 0);
1057 gtk_misc_set_padding(GTK_MISC(misc_report_label), 13, 13);
1058 gtk_label_set_selectable(GTK_LABEL(misc_report_label), TRUE);
1059 gtk_widget_modify_font (GTK_WIDGET(misc_report_label),
1060 font);
1062 /* Create GtkLabel to hold aperture defintion text */
1063 GtkWidget *aperture_def_report_label = gtk_label_new (aperture_def_report_string->str);
1064 g_string_free (aperture_def_report_string, TRUE);
1065 gtk_misc_set_alignment(GTK_MISC(aperture_def_report_label), 0, 0);
1066 gtk_misc_set_padding(GTK_MISC(aperture_def_report_label), 13, 13);
1067 gtk_label_set_selectable(GTK_LABEL(aperture_def_report_label), TRUE);
1068 gtk_widget_modify_font (GTK_WIDGET(aperture_def_report_label),
1069 font);
1070 /* Put aperture definintion text into scrolled window */
1071 GtkWidget *aperture_def_report_window = gtk_scrolled_window_new (NULL, NULL);
1072 /* This throws a warning. Must find different approach.... */
1073 gtk_widget_set_size_request(GTK_WIDGET(aperture_def_report_window),
1074 200,
1075 300);
1076 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(aperture_def_report_window),
1077 GTK_WIDGET(aperture_def_report_label));
1079 /* Create GtkLabel to hold aperture use text */
1080 GtkWidget *aperture_use_report_label = gtk_label_new (aperture_use_report_string->str);
1081 g_string_free (aperture_use_report_string, TRUE);
1082 gtk_misc_set_alignment(GTK_MISC(aperture_use_report_label), 0, 0);
1083 gtk_misc_set_padding(GTK_MISC(aperture_use_report_label), 13, 13);
1084 gtk_label_set_selectable(GTK_LABEL(aperture_use_report_label), TRUE);
1085 gtk_widget_modify_font (GTK_WIDGET(aperture_use_report_label),
1086 font);
1087 /* Put aperture definintion text into scrolled window */
1088 GtkWidget *aperture_use_report_window = gtk_scrolled_window_new (NULL, NULL);
1089 /* This throws a warning. Must find different approach.... */
1090 gtk_widget_set_size_request(GTK_WIDGET(aperture_use_report_window),
1091 200,
1092 300);
1093 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(aperture_use_report_window),
1094 GTK_WIDGET(aperture_use_report_label));
1096 /* Create tabbed notebook widget and add report label widgets. */
1097 GtkWidget *notebook = gtk_notebook_new();
1099 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1100 GTK_WIDGET(general_code_report_window),
1101 gtk_label_new("General"));
1103 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1104 GTK_WIDGET(G_report_label),
1105 gtk_label_new("G codes"));
1107 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1108 GTK_WIDGET(D_report_label),
1109 gtk_label_new("D codes"));
1111 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1112 GTK_WIDGET(M_report_label),
1113 gtk_label_new("M codes"));
1115 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1116 GTK_WIDGET(misc_report_label),
1117 gtk_label_new("Misc. codes"));
1119 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1120 GTK_WIDGET(aperture_def_report_window),
1121 gtk_label_new("Aperture definitions"));
1123 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1124 GTK_WIDGET(aperture_use_report_window),
1125 gtk_label_new("Aperture usage"));
1128 /* Now put notebook into dialog window and show the whole thing */
1129 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(analyze_active_gerbers)->vbox),
1130 GTK_WIDGET(notebook));
1132 gtk_widget_show_all(analyze_active_gerbers);
1134 /* free the stats report */
1135 gerbv_stats_destroy (stats_report);
1136 return;
1140 /* --------------------------------------------------------- */
1142 * The analyze -> analyze drill file menu item was selected.
1143 * Complie statistics on all open drill layers and then display
1144 * them.
1147 void
1148 callbacks_analyze_active_drill_activate(GtkMenuItem *menuitem,
1149 gpointer user_data)
1151 gerbv_drill_stats_t *stats_report;
1152 GString *G_report_string = g_string_new(NULL);
1153 GString *M_report_string = g_string_new(NULL);
1154 GString *misc_report_string = g_string_new(NULL);
1155 gerbv_drill_list_t *my_drill_list;
1156 GString *drill_report_string = g_string_new(NULL);
1157 GString *general_report_string = g_string_new(NULL);
1158 GString *error_report_string = g_string_new(NULL);
1159 gerbv_error_list_t *my_error_list;
1160 gchar *error_level = NULL;
1161 int idx;
1163 stats_report = (gerbv_drill_stats_t *) generate_drill_analysis();
1165 /* General and error window strings */
1166 g_string_printf(general_report_string, "General information\n");
1167 g_string_append_printf(general_report_string,
1168 " Active layer count = %d\n",
1169 stats_report->layer_count);
1171 g_string_append_printf(general_report_string,
1172 "\n\nFiles processed:\n");
1173 for (idx = mainProject->last_loaded; idx >= 0; idx--) {
1174 if (mainProject->file[idx] &&
1175 mainProject->file[idx]->isVisible &&
1176 (mainProject->file[idx]->image->layertype == GERBV_LAYERTYPE_DRILL) ) {
1177 g_string_append_printf(general_report_string,
1178 " %s\n",
1179 mainProject->file[idx]->name);
1184 if (stats_report->layer_count == 0) {
1185 g_string_printf(error_report_string, "\n\nNo drill files active (visible)!\n");
1186 } else if (stats_report->error_list->error_text == NULL) {
1187 g_string_printf(error_report_string,
1188 "\n\nNo errors found in active drill file(s)!\n");
1189 } else {
1190 g_string_printf(error_report_string,
1191 "\n\nErrors found in active drill file(s):\n");
1192 for(my_error_list = stats_report->error_list;
1193 my_error_list != NULL;
1194 my_error_list = my_error_list->next) {
1195 switch(my_error_list->type) {
1196 case GERBV_MESSAGE_FATAL: /* We should never get this one since the
1197 * program should terminate first.... */
1198 error_level = g_strdup_printf("FATAL: ");
1199 break;
1200 case GERBV_MESSAGE_ERROR:
1201 error_level = g_strdup_printf("ERROR: ");
1202 break;
1203 case GERBV_MESSAGE_WARNING:
1204 error_level = g_strdup_printf("WARNING: ");
1205 break;
1206 case GERBV_MESSAGE_NOTE:
1207 error_level = g_strdup_printf("NOTE: ");
1208 break;
1210 g_string_append_printf(error_report_string,
1211 " Layer %d: %s %s",
1212 my_error_list->layer,
1213 error_level,
1214 my_error_list->error_text);
1218 g_string_append_printf(general_report_string,
1219 "%s", error_report_string->str);
1220 g_string_free(error_report_string, TRUE);
1223 /* G code window strings */
1224 g_string_printf(G_report_string, "G code statistics (all active layers)\n");
1225 g_string_append_printf(G_report_string,
1226 "<code> = <number of incidences>\n");
1227 g_string_append_printf(G_report_string,
1228 "G00 = %-6d (%s)\n",
1229 stats_report->G00,
1230 "Rout mode");
1231 g_string_append_printf(G_report_string,
1232 "G01 = %-6d (%s)\n",
1233 stats_report->G01,
1234 "1X linear interpolation");
1235 g_string_append_printf(G_report_string,
1236 "G02 = %-6d (%s)\n",
1237 stats_report->G02,
1238 "CW interpolation");
1239 g_string_append_printf(G_report_string,
1240 "G03 = %-6d (%s)\n",
1241 stats_report->G03,
1242 "CCW interpolation");
1243 g_string_append_printf(G_report_string,
1244 "G04 = %-6d (%s)\n",
1245 stats_report->G04,
1246 "Variable dwell");
1247 g_string_append_printf(G_report_string,
1248 "G05 = %-6d (%s)\n",
1249 stats_report->G05,
1250 "Drill mode");
1251 g_string_append_printf(G_report_string,
1252 "G90 = %-6d (%s)\n",
1253 stats_report->G90,
1254 "Absolute units");
1255 g_string_append_printf(G_report_string,
1256 "G91 = %-6d (%s)\n",
1257 stats_report->G91,
1258 "Incremental units");
1259 g_string_append_printf(G_report_string,
1260 "G93 = %-6d (%s)\n",
1261 stats_report->G93,
1262 "Zero set");
1263 g_string_append_printf(G_report_string,
1264 "Unknown G codes = %d\n",
1265 stats_report->G_unknown);
1267 /* M code window strings */
1268 g_string_printf(M_report_string, "M code statistics (all active layers)\n");
1269 g_string_append_printf(M_report_string,
1270 "<code> = <number of incidences>\n");
1271 g_string_append_printf(M_report_string,
1272 "M00 = %-6d (%s)\n",
1273 stats_report->M00,
1274 "End of program");
1275 g_string_append_printf(M_report_string,
1276 "M01 = %-6d (%s)\n",
1277 stats_report->M01,
1278 "End of pattern");
1279 g_string_append_printf(M_report_string,
1280 "M18 = %-6d (%s)\n",
1281 stats_report->M18,
1282 "Tool tip check");
1283 g_string_append_printf(M_report_string,
1284 "M25 = %-6d (%s)\n",
1285 stats_report->M25,
1286 "Begin pattern");
1287 g_string_append_printf(M_report_string,
1288 "M30 = %-6d (%s)\n",
1289 stats_report->M30,
1290 "End program rewind");
1291 g_string_append_printf(M_report_string,
1292 "M31 = %-6d (%s)\n",
1293 stats_report->M31,
1294 "Begin pattern");
1295 g_string_append_printf(M_report_string,
1296 "M45 = %-6d (%s)\n",
1297 stats_report->M45,
1298 "Long message");
1299 g_string_append_printf(M_report_string,
1300 "M47 = %-6d (%s)\n",
1301 stats_report->M47,
1302 "Operator message");
1303 g_string_append_printf(M_report_string,
1304 "M48 = %-6d (%s)\n",
1305 stats_report->M48,
1306 "Begin program header");
1307 g_string_append_printf(M_report_string,
1308 "M71 = %-6d (%s)\n",
1309 stats_report->M71,
1310 "Metric units");
1311 g_string_append_printf(M_report_string,
1312 "M72 = %-6d (%s)\n",
1313 stats_report->M72,
1314 "English units");
1315 g_string_append_printf(M_report_string,
1316 "M95 = %-6d (%s)\n",
1317 stats_report->M95,
1318 "End program header");
1319 g_string_append_printf(M_report_string,
1320 "M97 = %-6d (%s)\n",
1321 stats_report->M97,
1322 "Canned text");
1323 g_string_append_printf(M_report_string,
1324 "M98 = %-6d (%s)\n",
1325 stats_report->M98,
1326 "Canned text");
1327 g_string_append_printf(M_report_string,
1328 "Unknown M codes = %d\n",
1329 stats_report->M_unknown);
1332 /* misc report strings */
1333 g_string_printf(misc_report_string, "Misc code statistics (all active layers)\n");
1334 g_string_append_printf(misc_report_string,
1335 "<code> = <number of incidences>\n");
1336 g_string_append_printf(misc_report_string,
1337 "comments = %d\n",
1338 stats_report->comment);
1339 g_string_append_printf(misc_report_string,
1340 "Unknown codes = %d\n",
1341 stats_report->unknown);
1343 g_string_append_printf(misc_report_string,
1344 "R = %-6d (%s)\n",
1345 stats_report->R,
1346 "Repeat hole");
1348 if (stats_report->detect != NULL ) {
1349 g_string_append_printf(misc_report_string,
1350 "\n%s\n",
1351 stats_report->detect);
1353 /* drill report window strings */
1354 g_string_printf(drill_report_string, "Drills used (all active layers)\n");
1355 g_string_append_printf(drill_report_string, "%10s %8s %8s %8s\n",
1356 "Drill no.", "Dia.", "Units", "Count");
1357 for(my_drill_list = stats_report->drill_list;
1358 my_drill_list != NULL;
1359 my_drill_list = my_drill_list->next) {
1360 if (my_drill_list->drill_num == -1) break; /* No drill list */
1361 g_string_append_printf(drill_report_string,
1362 "%10d %8.3f %8s %8d\n",
1363 my_drill_list->drill_num,
1364 my_drill_list->drill_size,
1365 my_drill_list->drill_unit,
1366 my_drill_list->drill_count);
1369 g_string_append_printf(drill_report_string, "Total drill count %d\n",
1370 stats_report->total_count);
1372 /* Use fixed width font for all reports */
1373 PangoFontDescription *font =
1374 pango_font_description_from_string ("monospace");
1376 /* Create top level dialog window for report */
1377 GtkWidget *analyze_active_drill;
1378 analyze_active_drill = gtk_dialog_new_with_buttons("Drill file codes report",
1379 NULL,
1380 GTK_DIALOG_DESTROY_WITH_PARENT,
1381 GTK_STOCK_OK,
1382 GTK_RESPONSE_ACCEPT,
1383 NULL);
1384 gtk_container_set_border_width (GTK_CONTAINER (analyze_active_drill), 5);
1385 gtk_dialog_set_default_response (GTK_DIALOG(analyze_active_drill),
1386 GTK_RESPONSE_ACCEPT);
1387 g_signal_connect (G_OBJECT(analyze_active_drill),
1388 "response",
1389 G_CALLBACK (gtk_widget_destroy),
1390 GTK_WIDGET(analyze_active_drill));
1392 /* Create GtkLabel to hold general report text */
1393 GtkWidget *general_report_label = gtk_label_new (general_report_string->str);
1394 g_string_free(general_report_string, TRUE);
1395 gtk_misc_set_alignment(GTK_MISC(general_report_label), 0, 0);
1396 gtk_misc_set_padding(GTK_MISC(general_report_label), 13, 13);
1397 gtk_label_set_selectable(GTK_LABEL(general_report_label), TRUE);
1398 gtk_widget_modify_font (GTK_WIDGET(general_report_label),
1399 font);
1401 /* Create GtkLabel to hold G code text */
1402 GtkWidget *G_report_label = gtk_label_new (G_report_string->str);
1403 g_string_free(G_report_string, TRUE);
1404 gtk_misc_set_alignment(GTK_MISC(G_report_label), 0, 0);
1405 gtk_misc_set_padding(GTK_MISC(G_report_label), 13, 13);
1406 gtk_label_set_selectable(GTK_LABEL(G_report_label), TRUE);
1407 gtk_widget_modify_font (GTK_WIDGET(G_report_label),
1408 font);
1410 /* Create GtkLabel to hold M code text */
1411 GtkWidget *M_report_label = gtk_label_new (M_report_string->str);
1412 g_string_free(M_report_string, TRUE);
1413 gtk_misc_set_alignment(GTK_MISC(M_report_label), 0, 0);
1414 gtk_misc_set_padding(GTK_MISC(M_report_label), 13, 13);
1415 gtk_label_set_selectable(GTK_LABEL(M_report_label), TRUE);
1416 gtk_widget_modify_font (GTK_WIDGET(M_report_label),
1417 font);
1419 /* Create GtkLabel to hold misc code text */
1420 GtkWidget *misc_report_label = gtk_label_new (misc_report_string->str);
1421 g_string_free(misc_report_string, TRUE);
1422 gtk_misc_set_alignment(GTK_MISC(misc_report_label), 0, 0);
1423 gtk_misc_set_padding(GTK_MISC(misc_report_label), 13, 13);
1424 gtk_label_set_selectable(GTK_LABEL(misc_report_label), TRUE);
1425 gtk_widget_modify_font (GTK_WIDGET(misc_report_label),
1426 font);
1428 /* Create GtkLabel to hold drills used text */
1429 GtkWidget *drill_report_label = gtk_label_new (drill_report_string->str);
1430 g_string_free(drill_report_string, TRUE);
1431 gtk_misc_set_alignment(GTK_MISC(drill_report_label), 0, 0);
1432 gtk_misc_set_padding(GTK_MISC(drill_report_label), 13, 13);
1433 gtk_label_set_selectable(GTK_LABEL(drill_report_label), TRUE);
1434 gtk_widget_modify_font (GTK_WIDGET(drill_report_label),
1435 font);
1437 /* Create tabbed notebook widget and add report label widgets. */
1438 GtkWidget *notebook = gtk_notebook_new();
1440 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1441 GTK_WIDGET(general_report_label),
1442 gtk_label_new("General"));
1444 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1445 GTK_WIDGET(G_report_label),
1446 gtk_label_new("G codes"));
1448 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1449 GTK_WIDGET(M_report_label),
1450 gtk_label_new("M codes"));
1452 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1453 GTK_WIDGET(misc_report_label),
1454 gtk_label_new("Misc. codes"));
1456 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1457 GTK_WIDGET(drill_report_label),
1458 gtk_label_new("Drills used"));
1460 /* Now put notebook into dialog window and show the whole thing */
1461 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(analyze_active_drill)->vbox),
1462 GTK_WIDGET(notebook));
1463 gtk_widget_show_all(analyze_active_drill);
1464 gerbv_drill_stats_destroy (stats_report);
1465 return;
1468 /* --------------------------------------------------------- */
1469 void
1470 callbacks_control_gerber_options_activate (GtkMenuItem *menuitem,
1471 gpointer user_data)
1476 /* --------------------------------------------------------- */
1477 void
1478 callbacks_online_manual_activate (GtkMenuItem *menuitem,
1479 gpointer user_data)
1484 /* --------------------------------------------------------- */
1486 * The file -> quit menu item was selected or
1487 * the user requested the main window to be closed by other means.
1488 * Check that all changes have been saved, and then quit.
1491 gboolean
1492 callbacks_quit_activate (GtkMenuItem *menuitem,
1493 gpointer user_data)
1495 gboolean layers_dirty = FALSE;
1496 gint idx;
1498 for (idx = 0; idx<=mainProject->last_loaded; idx++) {
1499 if (mainProject->file[idx] == NULL) break;
1500 layers_dirty = layers_dirty || mainProject->file[idx]->layer_dirty;
1503 if (layers_dirty &&
1504 !interface_get_alert_dialog_response(
1505 "Do you want to close all open layers and quit the program?",
1506 "Quitting the program will cause any unsaved changes to be lost.",
1507 FALSE,
1508 NULL)) {
1509 return TRUE; // stop propagation of the delete_event.
1510 // this would destroy the gui but not return from the gtk event loop.
1512 gerbv_unload_all_layers (mainProject);
1513 gtk_main_quit();
1514 return FALSE; // more or less... meaningless :)
1517 /* --------------------------------------------------------- */
1519 * The help -> about menu item was selected.
1520 * Show the about dialog.
1523 void
1524 callbacks_about_activate (GtkMenuItem *menuitem,
1525 gpointer user_data)
1527 GtkWidget *aboutdialog1;
1528 /* TRANSLATORS: Replace this string with your names, one name per line. */
1529 /* gchar *translators = _("translator-credits"); */
1531 gchar *string = g_strdup_printf ( "gerbv -- a Gerber (RS-274/X) viewer.\n\n"
1532 "This is gerbv version %s\n"
1533 "Compiled on %s at %s\n"
1534 "\n"
1535 "gerbv is part of the gEDA Project.\n"
1536 "\n"
1537 "For more information see:\n"
1538 " gerbv homepage: http://gerbv.gpleda.org/\n"
1539 " gEDA homepage: http://gpleda.org/\n"
1540 " gEDA Wiki: http://geda.seul.org/wiki/",
1541 VERSION, __DATE__, __TIME__);
1542 #if GTK_CHECK_VERSION(2,6,0)
1543 gchar *license = g_strdup_printf("gerbv -- a Gerber (RS-274/X) viewer.\n\n"
1544 "Copyright (C) 2000-2007 Stefan Petersen\n\n"
1545 "This program is free software: you can redistribute it and/or modify\n"
1546 "it under the terms of the GNU General Public License as published by\n"
1547 "the Free Software Foundation, either version 2 of the License, or\n"
1548 "(at your option) any later version.\n\n"
1549 "This program is distributed in the hope that it will be useful,\n"
1550 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1551 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1552 "GNU General Public License for more details.\n\n"
1553 "You should have received a copy of the GNU General Public License\n"
1554 "along with this program. If not, see <http://www.gnu.org/licenses/>.");
1555 #include "authors.c"
1557 aboutdialog1 = gtk_about_dialog_new ();
1558 gtk_container_set_border_width (GTK_CONTAINER (aboutdialog1), 5);
1559 gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (aboutdialog1), VERSION);
1560 gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (aboutdialog1), _("Gerbv"));
1562 /* gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG (aboutdialog1), translators); */
1563 gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (aboutdialog1), string);
1564 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG (aboutdialog1), license);
1566 /* The authors.c file is autogenerated at build time */
1567 gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG (aboutdialog1), authors_string_array);
1568 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG (aboutdialog1), "http://gerbv.gpleda.org/");
1570 g_signal_connect (G_OBJECT(aboutdialog1),"response",
1571 G_CALLBACK (gtk_widget_destroy), GTK_WIDGET(aboutdialog1));
1573 g_free (string);
1574 g_free (license);
1575 #else
1576 aboutdialog1 = gtk_message_dialog_new ( GTK_WINDOW (screen.win.topLevelWindow),
1577 GTK_DIALOG_DESTROY_WITH_PARENT,
1578 GTK_MESSAGE_INFO,
1579 GTK_BUTTONS_CLOSE,
1580 string
1583 gtk_window_set_title ( GTK_WINDOW (aboutdialog1), _("About Gerbv"));
1585 /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
1586 g_signal_connect_swapped (aboutdialog1, "response",
1587 G_CALLBACK (gtk_widget_destroy),
1588 aboutdialog1);
1589 g_free (string);
1590 #endif
1592 gtk_widget_show_all(GTK_WIDGET(aboutdialog1));
1596 /* --------------------------------------------------------- */
1598 * The help -> bugs menu item was selected.
1599 * Show the known bugs window
1602 void
1603 callbacks_bugs_activate (GtkMenuItem *menuitem,
1604 gpointer user_data)
1606 int i;
1607 #include "bugs.c"
1609 /* Create the top level dialog widget with an OK button */
1610 GtkWidget *bugs_dialog = gtk_dialog_new_with_buttons("Known bugs in gerbv",
1611 NULL,
1612 GTK_DIALOG_DESTROY_WITH_PARENT,
1613 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1614 NULL);
1615 gtk_container_set_border_width (GTK_CONTAINER (bugs_dialog), 5);
1616 gtk_dialog_set_default_response (GTK_DIALOG(bugs_dialog),
1617 GTK_RESPONSE_ACCEPT);
1618 g_signal_connect (G_OBJECT(bugs_dialog), "response",
1619 G_CALLBACK (gtk_widget_destroy), GTK_WIDGET(bugs_dialog));
1621 /* First create single bugs_string from bugs_string_array */
1622 GString *bugs_string = g_string_new(NULL);
1623 for (i=0; bugs_string_array[i] != NULL; i++) {
1624 g_string_append_printf(bugs_string,
1625 "%s\n",
1626 bugs_string_array[i]);
1629 /* Create GtkLabel to hold text */
1630 GtkWidget *bugs_label = gtk_label_new (bugs_string->str);
1631 g_string_free(bugs_string, TRUE);
1632 gtk_misc_set_alignment(GTK_MISC(bugs_label), 0, 0);
1633 gtk_misc_set_padding(GTK_MISC(bugs_label), 13, 13);
1635 /* Put text into scrolled window */
1636 GtkWidget *bugs_window = gtk_scrolled_window_new (NULL, NULL);
1637 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(bugs_window),
1638 GTK_WIDGET(bugs_label));
1639 gtk_widget_set_size_request(GTK_WIDGET(bugs_window), 600, 300);
1640 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(bugs_dialog)->vbox),
1641 GTK_WIDGET(bugs_window));
1643 gtk_widget_show_all(GTK_WIDGET(bugs_dialog));
1644 gtk_dialog_run(GTK_DIALOG(bugs_dialog));
1648 /* --------------------------------------------------------- */
1649 gdouble callbacks_calculate_actual_distance (gdouble inputDimension) {
1650 gdouble returnValue = 0.0;
1652 if (screen.unit == GERBV_MILS) {
1653 returnValue = COORD2MILS(inputDimension);
1654 } else if (screen.unit == GERBV_MMS) {
1655 returnValue = COORD2MMS(inputDimension);
1656 } else {
1657 returnValue = COORD2MILS(inputDimension)/1000;
1659 return returnValue;
1662 /* --------------------------------------------------------- */
1663 void callbacks_update_ruler_pointers (void) {
1664 double xPosition, yPosition;
1665 xPosition = screenRenderInfo.lowerLeftX + (screen.last_x / screenRenderInfo.scaleFactorX);
1666 yPosition = screenRenderInfo.lowerLeftY + ((screenRenderInfo.displayHeight - screen.last_y) / screenRenderInfo.scaleFactorY);
1668 if (!((screen.unit == GERBV_MILS) && ((screenRenderInfo.scaleFactorX < 80)||(screenRenderInfo.scaleFactorY < 80)))) {
1669 xPosition = callbacks_calculate_actual_distance (xPosition);
1670 yPosition = callbacks_calculate_actual_distance (yPosition);
1672 g_object_set (G_OBJECT (screen.win.hRuler), "position", xPosition, NULL);
1673 g_object_set (G_OBJECT (screen.win.vRuler), "position", yPosition, NULL);
1676 /* --------------------------------------------------------- */
1677 static void
1678 callbacks_render_type_changed () {
1679 static gboolean isChanging = FALSE;
1680 if (isChanging)
1681 return;
1683 isChanging = TRUE;
1684 gerbv_render_types_t type = screenRenderInfo.renderType;
1685 GtkCheckMenuItem *check_item = screen.win.menu_view_render_group[type];
1686 dprintf ("%s(): type = %d, check_item = %p\n", __FUNCTION__, type, check_item);
1687 gtk_check_menu_item_set_active (check_item, TRUE);
1688 gtk_combo_box_set_active (screen.win.sidepaneRenderComboBox, type);
1690 render_refresh_rendered_image_on_screen();
1691 isChanging = FALSE;
1694 /* --------------------------------------------------------- */
1695 static void
1696 callbacks_units_changed (gerbv_gui_unit_t unit) {
1697 static gboolean isChanging = FALSE;
1699 if (isChanging)
1700 return;
1702 isChanging = TRUE;
1703 screen.unit = unit;
1705 if (unit == GERBV_MILS){
1706 gtk_combo_box_set_active (GTK_COMBO_BOX (screen.win.statusUnitComboBox), GERBV_MILS);
1707 gtk_check_menu_item_set_active (screen.win.menu_view_unit_group[GERBV_MILS], TRUE);
1708 } else if (unit == GERBV_MMS){
1709 gtk_combo_box_set_active (GTK_COMBO_BOX (screen.win.statusUnitComboBox), GERBV_MMS);
1710 gtk_check_menu_item_set_active (screen.win.menu_view_unit_group[GERBV_MMS], TRUE);
1711 } else {
1712 gtk_combo_box_set_active (GTK_COMBO_BOX (screen.win.statusUnitComboBox), GERBV_INS);
1713 gtk_check_menu_item_set_active (screen.win.menu_view_unit_group[GERBV_INS], TRUE);
1716 callbacks_update_ruler_scales ();
1717 callbacks_update_statusbar_coordinates (screen.last_x, screen.last_y);
1719 if (screen.tool == MEASURE)
1720 callbacks_update_statusbar_measured_distance (screen.win.lastMeasuredX, screen.win.lastMeasuredY);
1722 isChanging = FALSE;
1725 /* --------------------------------------------------------- */
1726 static void
1727 callbacks_update_ruler_scales (void) {
1728 double xStart, xEnd, yStart, yEnd;
1730 xStart = screenRenderInfo.lowerLeftX;
1731 yStart = screenRenderInfo.lowerLeftY;
1732 xEnd = screenRenderInfo.lowerLeftX + (screenRenderInfo.displayWidth / screenRenderInfo.scaleFactorX);
1733 yEnd = screenRenderInfo.lowerLeftY + (screenRenderInfo.displayHeight / screenRenderInfo.scaleFactorY);
1734 /* mils can get super crowded with large boards, but inches are too
1735 large for most boards. So, we leave mils in for now and just switch
1736 to inches if the scale factor gets too small */
1737 if (!((screen.unit == GERBV_MILS) && ((screenRenderInfo.scaleFactorX < 80)||(screenRenderInfo.scaleFactorY < 80)))) {
1738 xStart = callbacks_calculate_actual_distance (xStart);
1739 xEnd = callbacks_calculate_actual_distance (xEnd);
1740 yStart = callbacks_calculate_actual_distance (yStart);
1741 yEnd = callbacks_calculate_actual_distance (yEnd);
1743 /* make sure the widgets actually exist before setting (in case this gets
1744 called before everything is realized */
1745 if (screen.win.hRuler)
1746 gtk_ruler_set_range (GTK_RULER (screen.win.hRuler), xStart, xEnd, 0, xEnd - xStart);
1747 /* reverse y min and max, since the ruler starts at the top */
1748 if (screen.win.vRuler)
1749 gtk_ruler_set_range (GTK_RULER (screen.win.vRuler), yEnd, yStart, 0, yEnd - yStart);
1752 /* --------------------------------------------------------- */
1753 void callbacks_update_scrollbar_limits (void){
1754 gerbv_render_info_t tempRenderInfo = {0, 0, 0, 0, 3, screenRenderInfo.displayWidth,
1755 screenRenderInfo.displayHeight};
1757 GtkAdjustment *hAdjust = (GtkAdjustment *)screen.win.hAdjustment;
1758 GtkAdjustment *vAdjust = (GtkAdjustment *)screen.win.vAdjustment;
1759 gerbv_render_zoom_to_fit_display (mainProject, &tempRenderInfo);
1760 hAdjust->lower = tempRenderInfo.lowerLeftX;
1761 hAdjust->page_increment = hAdjust->page_size;
1762 hAdjust->step_increment = hAdjust->page_size / 10.0;
1763 vAdjust->lower = tempRenderInfo.lowerLeftY;
1764 vAdjust->page_increment = vAdjust->page_size;
1765 vAdjust->step_increment = vAdjust->page_size / 10.0;
1766 hAdjust->upper = tempRenderInfo.lowerLeftX + (tempRenderInfo.displayWidth / tempRenderInfo.scaleFactorX);
1767 hAdjust->page_size = screenRenderInfo.displayWidth / screenRenderInfo.scaleFactorX;
1768 vAdjust->upper = tempRenderInfo.lowerLeftY + (tempRenderInfo.displayHeight / tempRenderInfo.scaleFactorY);
1769 vAdjust->page_size = screenRenderInfo.displayHeight / screenRenderInfo.scaleFactorY;
1770 callbacks_update_scrollbar_positions ();
1773 /* --------------------------------------------------------- */
1774 void callbacks_update_scrollbar_positions (void){
1775 gdouble positionX,positionY;
1777 positionX = screenRenderInfo.lowerLeftX;
1778 if (positionX < ((GtkAdjustment *)screen.win.hAdjustment)->lower)
1779 positionX = ((GtkAdjustment *)screen.win.hAdjustment)->lower;
1780 if (positionX > (((GtkAdjustment *)screen.win.hAdjustment)->upper - ((GtkAdjustment *)screen.win.hAdjustment)->page_size))
1781 positionX = (((GtkAdjustment *)screen.win.hAdjustment)->upper - ((GtkAdjustment *)screen.win.hAdjustment)->page_size);
1782 gtk_adjustment_set_value ((GtkAdjustment *)screen.win.hAdjustment, positionX);
1784 positionY = ((GtkAdjustment *)screen.win.vAdjustment)->upper - screenRenderInfo.lowerLeftY -
1785 ((GtkAdjustment *)screen.win.vAdjustment)->page_size +
1786 ((GtkAdjustment *)screen.win.vAdjustment)->lower;
1787 if (positionY < ((GtkAdjustment *)screen.win.vAdjustment)->lower)
1788 positionY = ((GtkAdjustment *)screen.win.vAdjustment)->lower;
1789 if (positionY > (((GtkAdjustment *)screen.win.vAdjustment)->upper - ((GtkAdjustment *)screen.win.vAdjustment)->page_size))
1790 positionY = (((GtkAdjustment *)screen.win.vAdjustment)->upper - ((GtkAdjustment *)screen.win.vAdjustment)->page_size);
1791 gtk_adjustment_set_value ((GtkAdjustment *)screen.win.vAdjustment, positionY);
1794 /* --------------------------------------------------------- */
1795 gboolean
1796 callbacks_scrollbar_button_released (GtkWidget *widget, GdkEventButton *event){
1797 screen.off_x = 0;
1798 screen.off_y = 0;
1799 screen.state = NORMAL;
1800 render_refresh_rendered_image_on_screen();
1801 return FALSE;
1804 /* --------------------------------------------------------- */
1805 gboolean
1806 callbacks_scrollbar_button_pressed (GtkWidget *widget, GdkEventButton *event){
1807 //screen.last_x = ((GtkAdjustment *)screen.win.hAdjustment)->value;
1808 screen.state = SCROLLBAR;
1809 return FALSE;
1812 /* --------------------------------------------------------- */
1813 void callbacks_hadjustment_value_changed (GtkAdjustment *adjustment, gpointer user_data){
1814 /* make sure we're actually using the scrollbar to make sure we don't reset
1815 lowerLeftX during a scrollbar redraw during something else */
1816 if (screen.state == SCROLLBAR) {
1817 screenRenderInfo.lowerLeftX = gtk_adjustment_get_value (adjustment);
1821 /* --------------------------------------------------------- */
1822 void callbacks_vadjustment_value_changed (GtkAdjustment *adjustment, gpointer user_data){
1823 /* make sure we're actually using the scrollbar to make sure we don't reset
1824 lowerLeftY during a scrollbar redraw during something else */
1825 if (screen.state == SCROLLBAR) {
1826 screenRenderInfo.lowerLeftY = adjustment->upper -
1827 (gtk_adjustment_get_value (adjustment) + adjustment->page_size) + adjustment->lower;
1831 /* --------------------------------------------------------- */
1832 void
1833 callbacks_layer_tree_visibility_button_toggled (GtkCellRendererToggle *cell_renderer,
1834 gchar *path,
1835 gpointer user_data){
1836 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
1837 ((GtkTreeView *) screen.win.layerTree);
1838 GtkTreeIter iter;
1839 gboolean newVisibility=TRUE;
1840 gint index;
1842 gtk_tree_model_get_iter_from_string ((GtkTreeModel *)list_store, &iter, path);
1844 GtkTreePath *treePath = gtk_tree_path_new_from_string (path);
1845 if (gtk_tree_model_get_iter((GtkTreeModel *)list_store, &iter, treePath)) {
1846 gint *indices;
1848 indices = gtk_tree_path_get_indices (treePath);
1849 index = indices[0];
1850 if (mainProject->file[index]->isVisible)
1851 newVisibility = FALSE;
1852 mainProject->file[index]->isVisible = newVisibility;
1853 /* clear any selected items so they don't show after the layer is hidden */
1854 render_clear_selection_buffer();
1856 callbacks_update_layer_tree ();
1857 if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
1858 render_refresh_rendered_image_on_screen();
1860 else {
1861 render_recreate_composite_surface (screen.drawing_area);
1862 callbacks_force_expose_event_for_screen ();
1867 /* --------------------------------------------------------- */
1868 gint
1869 callbacks_get_col_number_from_tree_view_column (GtkTreeViewColumn *col)
1871 GList *cols;
1872 gint num;
1874 g_return_val_if_fail ( col != NULL, -1 );
1875 g_return_val_if_fail ( col->tree_view != NULL, -1 );
1876 cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(col->tree_view));
1877 num = g_list_index(cols, (gpointer) col);
1878 g_list_free(cols);
1879 return num;
1882 /* --------------------------------------------------------- */
1883 void
1884 callbacks_add_layer_button_clicked (GtkButton *button, gpointer user_data) {
1885 callbacks_open_layer_activate (NULL, NULL);
1888 /* --------------------------------------------------------- */
1889 void
1890 callbacks_unselect_all_tool_buttons (void) {
1894 void
1895 callbacks_switch_to_normal_tool_cursor (gint toolNumber) {
1896 GdkCursor *cursor;
1898 switch (toolNumber) {
1899 case POINTER:
1900 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1901 GERBV_DEF_CURSOR);
1902 break;
1903 case PAN:
1904 cursor = gdk_cursor_new(GDK_FLEUR);
1905 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1906 cursor);
1907 gdk_cursor_destroy(cursor);
1908 break;
1909 case ZOOM:
1910 cursor = gdk_cursor_new(GDK_SIZING);
1911 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1912 cursor);
1913 gdk_cursor_destroy(cursor);
1914 break;
1915 case MEASURE:
1916 cursor = gdk_cursor_new(GDK_CROSSHAIR);
1917 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1918 cursor);
1919 gdk_cursor_destroy(cursor);
1920 break;
1921 default:
1922 break;
1926 /* --------------------------------------------------------- */
1927 void
1928 callbacks_switch_to_correct_cursor (void) {
1929 GdkCursor *cursor;
1931 if (screen.state == IN_MOVE) {
1932 cursor = gdk_cursor_new(GDK_FLEUR);
1933 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1934 cursor);
1935 gdk_cursor_destroy(cursor);
1936 return;
1938 else if (screen.state == IN_ZOOM_OUTLINE) {
1939 cursor = gdk_cursor_new(GDK_SIZING);
1940 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1941 cursor);
1942 gdk_cursor_destroy(cursor);
1943 return;
1945 callbacks_switch_to_normal_tool_cursor (screen.tool);
1948 /* --------------------------------------------------------- */
1949 void
1950 callbacks_change_tool (GtkButton *button, gpointer user_data) {
1951 gint toolNumber = GPOINTER_TO_INT (user_data);
1953 /* make sure se don't get caught in endless recursion here */
1954 if (screen.win.updatingTools)
1955 return;
1956 screen.win.updatingTools = TRUE;
1957 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPointer), FALSE);
1958 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPan), FALSE);
1959 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonZoom), FALSE);
1960 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonMeasure), FALSE);
1961 switch (toolNumber) {
1962 case POINTER:
1963 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPointer), TRUE);
1964 screen.tool = POINTER;
1965 screen.state = NORMAL;
1966 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
1967 "Click to select objects in the current layer. Middle click and drag to pan.");
1968 break;
1969 case PAN:
1970 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPan), TRUE);
1971 screen.tool = PAN;
1972 screen.state = NORMAL;
1973 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
1974 "Click and drag to pan. Right click and drag to zoom.");
1975 break;
1976 case ZOOM:
1977 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonZoom), TRUE);
1978 screen.tool = ZOOM;
1979 screen.state = NORMAL;
1980 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
1981 "Click and drag to zoom in. Shift+click to zoom out.");
1982 break;
1983 case MEASURE:
1984 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonMeasure), TRUE);
1985 screen.tool = MEASURE;
1986 screen.state = NORMAL;
1987 snprintf(screen.statusbar.diststr, MAX_DISTLEN, "Click and drag to measure a distance.");
1988 break;
1989 default:
1990 break;
1992 callbacks_switch_to_normal_tool_cursor (toolNumber);
1993 callbacks_update_statusbar();
1994 screen.win.updatingTools = FALSE;
1995 callbacks_force_expose_event_for_screen();
1998 /* --------------------------------------------------------- */
1999 void
2000 callbacks_select_row (gint rowIndex) {
2001 GtkTreeSelection *selection;
2002 GtkTreeIter iter;
2003 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2004 ((GtkTreeView *) screen.win.layerTree);
2006 selection = gtk_tree_view_get_selection((GtkTreeView *) screen.win.layerTree);
2007 if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store), &iter, NULL, rowIndex)) {
2008 gtk_tree_selection_select_iter (selection, &iter);
2012 /* --------------------------------------------------------- */
2014 * This fcn returns the index of selected layer (selected in
2015 * the layer window on left).
2018 gint
2019 callbacks_get_selected_row_index (void) {
2020 GtkTreeSelection *selection;
2021 GtkTreeIter iter;
2022 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2023 ((GtkTreeView *) screen.win.layerTree);
2024 gint index=-1,i=0;
2026 /* This will only work in single or browse selection mode! */
2027 selection = gtk_tree_view_get_selection((GtkTreeView *) screen.win.layerTree);
2028 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
2029 while (gtk_tree_model_iter_nth_child ((GtkTreeModel *)list_store,
2030 &iter, NULL, i)){
2031 if (gtk_tree_selection_iter_is_selected (selection, &iter)) {
2032 return i;
2034 i++;
2037 return index;
2040 /* --------------------------------------------------------- */
2041 void
2042 callbacks_remove_layer_button_clicked (GtkButton *button, gpointer user_data) {
2043 gint index=callbacks_get_selected_row_index();
2045 if ((index >= 0) && (index <= mainProject->last_loaded)) {
2046 render_remove_selected_objects_belonging_to_layer (index);
2047 gerbv_unload_layer (mainProject, index);
2048 callbacks_update_layer_tree ();
2049 callbacks_select_row (0);
2051 if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2052 render_refresh_rendered_image_on_screen();
2054 else {
2055 render_recreate_composite_surface (screen.drawing_area);
2056 callbacks_force_expose_event_for_screen ();
2061 /* --------------------------------------------------------- */
2062 void
2063 callbacks_move_layer_down_menu_activate (GtkMenuItem *menuitem, gpointer user_data) {
2064 callbacks_move_layer_down_button_clicked(NULL, NULL);
2065 gtk_widget_grab_focus (screen.win.layerTree);
2068 /* --------------------------------------------------------- */
2069 void
2070 callbacks_move_layer_down_button_clicked (GtkButton *button, gpointer user_data) {
2071 gint index=callbacks_get_selected_row_index();
2072 if (index < 0) {
2073 show_no_layers_warning ();
2074 return;
2077 if (index < mainProject->last_loaded) {
2078 gerbv_change_layer_order (mainProject, index, index + 1);
2079 callbacks_update_layer_tree ();
2080 callbacks_select_row (index + 1);
2081 if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2082 render_refresh_rendered_image_on_screen ();
2084 else {
2085 render_recreate_composite_surface (screen.drawing_area);
2086 callbacks_force_expose_event_for_screen ();
2091 /* --------------------------------------------------------- */
2092 void
2093 callbacks_move_layer_up_menu_activate (GtkMenuItem *menuitem, gpointer user_data) {
2094 callbacks_move_layer_up_button_clicked (NULL, NULL);
2095 gtk_widget_grab_focus (screen.win.layerTree);
2098 /* --------------------------------------------------------- */
2099 void
2100 callbacks_move_layer_up_button_clicked (GtkButton *button, gpointer user_data) {
2101 gint index=callbacks_get_selected_row_index();
2102 if (index < 0) {
2103 show_no_layers_warning ();
2104 return;
2106 if (index > 0) {
2107 gerbv_change_layer_order (mainProject, index, index - 1);
2108 callbacks_update_layer_tree ();
2109 callbacks_select_row (index - 1);
2110 if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2111 render_refresh_rendered_image_on_screen();
2113 else {
2114 render_recreate_composite_surface (screen.drawing_area);
2115 callbacks_force_expose_event_for_screen ();
2120 /* --------------------------------------------------------- */
2121 void callbacks_layer_tree_row_inserted (GtkTreeModel *tree_model, GtkTreePath *path,
2122 GtkTreeIter *oIter, gpointer user_data) {
2123 gint *indices=NULL,oldPosition,newPosition;
2125 if ((!screen.win.treeIsUpdating)&&(path != NULL)) {
2126 indices = gtk_tree_path_get_indices (path);
2127 if (indices) {
2128 newPosition = indices[0];
2129 oldPosition = callbacks_get_selected_row_index ();
2130 /* compensate for the fact that the old row has already
2131 been removed */
2132 if (oldPosition < newPosition)
2133 newPosition--;
2134 else
2135 oldPosition--;
2136 gerbv_change_layer_order (mainProject, oldPosition, newPosition);
2138 if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2139 render_refresh_rendered_image_on_screen();
2141 else {
2142 render_recreate_composite_surface (screen.drawing_area);
2143 callbacks_force_expose_event_for_screen ();
2145 /* select the new line */
2146 GtkTreeSelection *selection;
2147 GtkTreeIter iter;
2148 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2149 ((GtkTreeView *) screen.win.layerTree);
2151 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(screen.win.layerTree));
2152 if (gtk_tree_model_get_iter ((GtkTreeModel *)list_store, &iter, path))
2153 gtk_tree_selection_select_iter (selection, &iter);
2158 /* --------------------------------------------------------- */
2159 void
2160 callbacks_show_color_picker_dialog (gint index){
2161 screen.win.colorSelectionDialog = NULL;
2162 GtkColorSelectionDialog *cs= (GtkColorSelectionDialog *) gtk_color_selection_dialog_new ("Select a color");
2163 GtkColorSelection *colorsel = (GtkColorSelection *) cs->colorsel;
2165 screen.win.colorSelectionDialog = (GtkWidget *) cs;
2166 screen.win.colorSelectionIndex = index;
2167 if (index >= 0)
2168 gtk_color_selection_set_current_color (colorsel, &mainProject->file[index]->color);
2169 else
2170 gtk_color_selection_set_current_color (colorsel, &mainProject->background);
2171 if ((screenRenderInfo.renderType >= GERBV_RENDER_TYPE_CAIRO_NORMAL)&&(index >= 0)) {
2172 gtk_color_selection_set_has_opacity_control (colorsel, TRUE);
2173 gtk_color_selection_set_current_alpha (colorsel, mainProject->file[index]->alpha);
2175 gtk_widget_show_all((GtkWidget *)cs);
2176 if (gtk_dialog_run ((GtkDialog*)cs) == GTK_RESPONSE_OK) {
2177 GtkColorSelection *colorsel = (GtkColorSelection *) cs->colorsel;
2178 gint rowIndex = screen.win.colorSelectionIndex;
2180 if (index >= 0) {
2181 gtk_color_selection_get_current_color (colorsel, &mainProject->file[rowIndex]->color);
2182 gdk_colormap_alloc_color(gdk_colormap_get_system(), &mainProject->file[rowIndex]->color, FALSE, TRUE);
2184 else {
2185 gtk_color_selection_get_current_color (colorsel, &mainProject->background);
2186 gdk_colormap_alloc_color(gdk_colormap_get_system(), &mainProject->background, FALSE, TRUE);
2188 if ((screenRenderInfo.renderType >= GERBV_RENDER_TYPE_CAIRO_NORMAL)&&(index >= 0)) {
2189 mainProject->file[rowIndex]->alpha = gtk_color_selection_get_current_alpha (colorsel);
2192 callbacks_update_layer_tree ();
2193 render_refresh_rendered_image_on_screen();
2195 gtk_widget_destroy ((GtkWidget *)cs);
2196 screen.win.colorSelectionDialog = NULL;
2199 /* --------------------------------------------------------- */
2200 void
2201 callbacks_invert_layer_clicked (GtkButton *button, gpointer user_data) {
2202 gint index=callbacks_get_selected_row_index();
2203 if (index < 0) {
2204 show_no_layers_warning ();
2205 return;
2207 mainProject->file[index]->transform.inverted = !mainProject->file[index]->transform.inverted;
2208 render_refresh_rendered_image_on_screen ();
2209 callbacks_update_layer_tree ();
2212 /* --------------------------------------------------------- */
2213 void
2214 callbacks_change_layer_color_clicked (GtkButton *button, gpointer user_data) {
2215 gint index=callbacks_get_selected_row_index();
2216 if (index < 0) {
2217 show_no_layers_warning ();
2218 return;
2220 callbacks_show_color_picker_dialog (index);
2223 void
2224 callbacks_change_background_color_clicked (GtkButton *button, gpointer user_data) {
2225 callbacks_show_color_picker_dialog (-1);
2228 /* --------------------------------------------------------------------------- */
2229 void
2230 callbacks_reload_layer_clicked (GtkButton *button, gpointer user_data) {
2231 gint index = callbacks_get_selected_row_index();
2232 if (index < 0) {
2233 show_no_layers_warning ();
2234 return;
2236 render_remove_selected_objects_belonging_to_layer (index);
2237 gerbv_revert_file (mainProject, index);
2238 render_refresh_rendered_image_on_screen ();
2239 callbacks_update_layer_tree();
2242 void
2243 callbacks_change_layer_orientation_clicked (GtkButton *button, gpointer userData){
2244 gint index = callbacks_get_selected_row_index();
2246 if (index < 0) {
2247 show_no_layers_warning ();
2248 return;
2251 interface_show_modify_orientation_dialog(&mainProject->file[index]->transform,screen.unit);
2252 render_refresh_rendered_image_on_screen ();
2253 callbacks_update_layer_tree ();
2256 /* --------------------------------------------------------------------------- */
2257 void
2258 callbacks_change_layer_format_clicked (GtkButton *button, gpointer user_data)
2260 gerbv_HID_Attribute *attr = NULL;
2261 int n = 0;
2262 int i;
2263 gerbv_HID_Attr_Val * results = NULL;
2264 gint index = callbacks_get_selected_row_index();
2265 gchar *type;
2266 gint rc;
2267 if (index < 0) {
2268 show_no_layers_warning ();
2269 return;
2271 dprintf ("%s(): index = %d\n", __FUNCTION__, index);
2272 attr = mainProject->file[index]->image->info->attr_list;
2273 n = mainProject->file[index]->image->info->n_attr;
2274 type = mainProject->file[index]->image->info->type;
2275 if (type == NULL)
2276 type = "Unknown";
2278 if (attr == NULL || n == 0)
2280 interface_show_alert_dialog("This file type does not currently have any editable features",
2281 "Format editing is currently only supported for Excellon drill file formats.",
2282 FALSE,
2283 NULL);
2284 return;
2287 dprintf ("%s(): n = %d, attr = %p\n", __FUNCTION__, n, attr);
2288 if (n > 0)
2290 if (mainProject->file[index]->layer_dirty) {
2291 rc = interface_get_alert_dialog_response ("This layer has changed!",
2292 "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.",
2293 TRUE,
2294 NULL);
2295 if (rc == 0) return; /* Return if user hit Cancel */
2298 results = (gerbv_HID_Attr_Val *) malloc (n * sizeof (gerbv_HID_Attr_Val));
2299 if (results == NULL)
2301 fprintf (stderr, "%s() -- malloc failed\n", __FUNCTION__);
2302 exit (1);
2305 /* non-zero means cancel was picked */
2306 if (attribute_interface_dialog (attr, n, results,
2307 "Edit file format",
2308 type))
2310 return;
2315 dprintf ("%s(): Reloading layer\n", __FUNCTION__);
2316 gerbv_revert_file (mainProject, index);
2318 for (i = 0; i < n; i++)
2320 if (results[i].str_value)
2321 free (results[i].str_value);
2324 if (results)
2325 free (results);
2326 render_refresh_rendered_image_on_screen();
2327 callbacks_update_layer_tree();
2330 /* --------------------------------------------------------------------------- */
2331 gboolean
2332 callbacks_layer_tree_key_press (GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
2333 /* if space is pressed while a color picker icon is in focus,
2334 show the color picker dialog. */
2335 if(event->keyval == GDK_space){
2336 GtkTreeView *tree;
2337 GtkTreePath *path;
2338 GtkTreeViewColumn *col;
2339 gint *indices;
2340 gint idx;
2342 tree = (GtkTreeView *) screen.win.layerTree;
2343 gtk_tree_view_get_cursor (tree, &path, &col);
2344 if (path) {
2345 indices = gtk_tree_path_get_indices (path);
2346 if (indices) {
2347 idx = callbacks_get_col_number_from_tree_view_column (col);
2348 if ((idx == 1) && (indices[0] <= mainProject->last_loaded)){
2349 callbacks_show_color_picker_dialog (indices[0]);
2352 gtk_tree_path_free (path);
2355 /* by default propagate the key press */
2356 return FALSE;
2359 /* --------------------------------------------------------------------------- */
2360 gboolean
2361 callbacks_layer_tree_button_press (GtkWidget *widget, GdkEventButton *event,
2362 gpointer user_data) {
2363 GtkTreePath *path;
2364 GtkTreeIter iter;
2365 GtkTreeViewColumn *column;
2366 gint x,y;
2367 gint columnIndex;
2369 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2370 ((GtkTreeView *) screen.win.layerTree);
2371 if (event->button == 1) {
2372 if (gtk_tree_view_get_path_at_pos ((GtkTreeView *) widget, event->x, event->y,
2373 &path, &column, &x, &y)) {
2374 if (gtk_tree_model_get_iter((GtkTreeModel *)list_store, &iter, path)) {
2375 gint *indices;
2376 indices = gtk_tree_path_get_indices (path);
2377 if (indices) {
2378 columnIndex = callbacks_get_col_number_from_tree_view_column (column);
2379 if ((columnIndex == 1) && (indices[0] <= mainProject->last_loaded)){
2380 callbacks_show_color_picker_dialog (indices[0]);
2381 /* don't propagate the signal, since drag and drop can
2382 sometimes activated during color selection */
2383 return TRUE;
2389 /* don't pop up the menu if we don't have any loaded files */
2390 else if ((event->button == 3)&&(mainProject->last_loaded >= 0)) {
2391 gtk_menu_popup(GTK_MENU(screen.win.layerTreePopupMenu), NULL, NULL, NULL, NULL,
2392 event->button, event->time);
2394 /* always allow the click to propagate and make sure the line is activated */
2395 return FALSE;
2398 /* --------------------------------------------------------------------------- */
2399 void
2400 callbacks_update_layer_tree (void) {
2401 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2402 ((GtkTreeView *) screen.win.layerTree);
2403 gint idx;
2404 GtkTreeIter iter;
2405 GtkTreeSelection *selection;
2406 gint oldSelectedRow;
2408 if (!screen.win.treeIsUpdating) {
2409 screen.win.treeIsUpdating = TRUE;
2411 oldSelectedRow = callbacks_get_selected_row_index();
2412 if (oldSelectedRow < 0)
2413 oldSelectedRow = 0;
2414 gtk_list_store_clear (list_store);
2416 for (idx = 0; idx <= mainProject->last_loaded; idx++) {
2417 if (mainProject->file[idx]) {
2418 GdkPixbuf *pixbuf,*blackPixbuf;
2419 guint32 color;
2421 unsigned char red, green, blue, alpha;
2423 red = (unsigned char) (mainProject->file[idx]->color.red * 255 / G_MAXUINT16) ;
2424 green = (unsigned char) (mainProject->file[idx]->color.green * 255 / G_MAXUINT16) ;
2425 blue = (unsigned char) (mainProject->file[idx]->color.blue *255 / G_MAXUINT16) ;
2426 alpha = (unsigned char) (mainProject->file[idx]->alpha * 255 / G_MAXUINT16) ;
2428 color = (red )* (256*256*256) + (green ) * (256*256) + (blue )* (256) + (alpha );
2429 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 20, 15);
2430 gdk_pixbuf_fill (pixbuf, color);
2432 blackPixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 20, 15);
2433 color = (100 )* (256*256*256) + (100 ) * (256*256) + (100 )* (256) + (150 );
2434 gdk_pixbuf_fill (blackPixbuf, color);
2436 /* copy the color area into the black pixbuf */
2437 gdk_pixbuf_copy_area (pixbuf, 1, 1, 18, 13, blackPixbuf, 1, 1);
2438 /* free the color buffer, since we don't need it anymore */
2439 g_object_unref(pixbuf);
2441 gtk_list_store_append (list_store, &iter);
2443 gchar startChar[2],*modifiedCode;
2444 /* terminate the letter string */
2445 startChar[1] = 0;
2447 gint numberOfModifications = 0;
2448 if (mainProject->file[idx]->transform.inverted) {
2449 startChar[0] = 'I';
2450 numberOfModifications++;
2452 if (mainProject->file[idx]->transform.mirrorAroundX ||
2453 mainProject->file[idx]->transform.mirrorAroundY) {
2454 startChar[0] = 'M';
2455 numberOfModifications++;
2457 if ((fabs(mainProject->file[idx]->transform.translateX) > 0.000001) ||
2458 (fabs(mainProject->file[idx]->transform.translateY) > 0.000001)) {
2459 startChar[0] = 'T';
2460 numberOfModifications++;
2462 if ((fabs(mainProject->file[idx]->transform.scaleX - 1) > 0.000001) ||
2463 (fabs(mainProject->file[idx]->transform.scaleY - 1) > 0.000001)) {
2464 startChar[0] = 'S';
2465 numberOfModifications++;
2467 if ((fabs(mainProject->file[idx]->transform.rotation) > 0.000001)) {
2468 startChar[0] = 'R';
2469 numberOfModifications++;
2471 if (numberOfModifications > 1)
2472 startChar[0] = '*';
2473 if (numberOfModifications == 0)
2474 modifiedCode = g_strdup ("");
2475 else
2476 modifiedCode = g_strdup (startChar);
2478 /* display any unsaved layers differently to show the user they are
2479 unsaved */
2480 gchar *layerName;
2481 if (mainProject->file[idx]->layer_dirty == TRUE) {
2482 /* The layer has unsaved changes in it. Show layer name in italics. */
2483 layerName = g_strconcat ("*","<i>",mainProject->file[idx]->name,"</i>",NULL);
2485 else
2486 /* layer is clean. Show layer name using normal font. */
2487 layerName = g_strdup (mainProject->file[idx]->name);
2489 gtk_list_store_set (list_store, &iter,
2490 0, mainProject->file[idx]->isVisible,
2491 1, blackPixbuf,
2492 2, layerName,
2493 3, modifiedCode,
2494 -1);
2495 g_free (layerName);
2496 g_free (modifiedCode);
2497 /* pixbuf has a refcount of 2 now, as the list store has added its own reference */
2498 g_object_unref(blackPixbuf);
2502 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(screen.win.layerTree));
2504 /* if no line is selected yet, select the first row (if it has data) */
2505 /* or, select the line that was previously selected */
2507 if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
2508 if (gtk_tree_model_iter_nth_child ((GtkTreeModel *) list_store,
2509 &iter, NULL, oldSelectedRow)) {
2510 gtk_tree_selection_select_iter (selection, &iter);
2513 gboolean showItems = (mainProject->last_loaded >= 0);
2514 gtk_widget_set_sensitive (screen.win.curLayerMenuItem, showItems);
2515 gtk_widget_set_sensitive (screen.win.curAnalyzeMenuItem, showItems);
2516 gtk_widget_set_sensitive (screen.win.curEditMenuItem, showItems);
2517 gtk_widget_set_sensitive (screen.win.curFileMenuItem1, showItems);
2518 gtk_widget_set_sensitive (screen.win.curFileMenuItem2, showItems);
2519 gtk_widget_set_sensitive (screen.win.curFileMenuItem3, showItems);
2520 gtk_widget_set_sensitive (screen.win.curFileMenuItem4, showItems);
2521 gtk_widget_set_sensitive (screen.win.curFileMenuItem5, showItems);
2522 gtk_widget_set_sensitive (screen.win.curFileMenuItem6, showItems);
2523 gtk_widget_set_sensitive (screen.win.curFileMenuItem7, showItems);
2524 screen.win.treeIsUpdating = FALSE;
2528 /* --------------------------------------------------------------------------- */
2529 void
2530 callbacks_display_object_properties_clicked (GtkButton *button, gpointer user_data) {
2531 int i;
2532 gchar *layer_name;
2533 gchar *net_label;
2534 gboolean validAperture;
2536 gint index=callbacks_get_selected_row_index ();
2537 if (index < 0 || screen.selectionInfo.type == GERBV_SELECTION_EMPTY) {
2538 interface_show_alert_dialog("No object is currently selected",
2539 "Objects must be selected using the pointer tool before you can view the object properties.",
2540 FALSE,
2541 NULL);
2542 return;
2545 for (i=0; i<screen.selectionInfo.selectedNodeArray->len; i++){
2546 gerbv_selection_item_t sItem = g_array_index (screen.selectionInfo.selectedNodeArray,
2547 gerbv_selection_item_t, i);
2549 gerbv_net_t *net = sItem.net;
2550 gerbv_image_t *image = sItem.image;
2551 int ap_type=0;
2553 /* get the aperture definition for the selected item */
2554 if (net->aperture > 0) {
2555 ap_type = image->aperture[net->aperture]->type;
2556 validAperture = TRUE;
2558 else {
2559 validAperture = FALSE;
2562 /* Also get layer name specified in file by %LN directive
2563 * (if it exists). */
2564 if (net->layer->name == NULL) {
2565 layer_name = g_strdup("<unnamed layer>");
2566 } else {
2567 layer_name = g_strdup(net->layer->name);
2570 if (net->label == NULL) {
2571 net_label = g_strdup("<unlabeled net>");
2572 } else {
2573 net_label = g_strdup((gchar *)net->label);
2575 if (net->interpolation == GERBV_INTERPOLATION_PAREA_START) {
2576 g_message ("Object type: Polygon\n");
2578 else {
2579 switch (net->aperture_state){
2580 case GERBV_APERTURE_STATE_OFF:
2581 break;
2582 case GERBV_APERTURE_STATE_ON:
2583 if (i!=0) g_message ("\n"); /* Spacing for a pretty display */
2584 switch (net->interpolation) {
2585 case GERBV_INTERPOLATION_x10 :
2586 case GERBV_INTERPOLATION_LINEARx01 :
2587 case GERBV_INTERPOLATION_LINEARx001 :
2588 case GERBV_INTERPOLATION_LINEARx1 :
2589 g_message ("Object type: Line\n");
2590 break;
2591 case GERBV_INTERPOLATION_CW_CIRCULAR :
2592 case GERBV_INTERPOLATION_CCW_CIRCULAR :
2593 g_message ("Object type: Arc\n");
2594 break;
2595 default :
2596 g_message ("Object type: Unknown\n");
2597 break;
2599 g_message (" Exposure: On\n");
2600 if (validAperture) {
2601 g_message (" Aperture used: D%d\n", net->aperture);
2602 g_message (" Aperture type: %s\n", ap_names[ap_type]);
2604 g_message (" Start location: (%g, %g)\n", net->start_x, net->start_y);
2605 g_message (" Stop location: (%g, %g)\n", net->stop_x, net->stop_y);
2606 g_message (" Layer name: %s\n", layer_name);
2607 g_message (" Net label: %s\n", net_label);
2608 g_message (" In file: %s\n", mainProject->file[index]->name);
2609 break;
2610 case GERBV_APERTURE_STATE_FLASH:
2611 if (i!=0) g_message ("\n"); /* Spacing for a pretty display */
2612 g_message ("Object type: Flashed aperture\n");
2613 if (validAperture) {
2614 g_message (" Aperture used: D%d\n", net->aperture);
2615 g_message (" Aperture type: %s\n", ap_names[ap_type]);
2617 g_message (" Location: (%g, %g)\n", net->stop_x, net->stop_y);
2618 g_message (" Layer name: %s\n", layer_name);
2619 g_message (" Net label: %s\n", net_label);
2620 g_message (" In file: %s\n", mainProject->file[index]->name);
2621 break;
2624 g_free (net_label);
2625 g_free (layer_name);
2627 /* Use separator for different report requests */
2628 g_message ("---------------------------------------\n");
2631 void
2632 callbacks_support_benchmark (gerbv_render_info_t *renderInfo) {
2633 int i;
2634 time_t start, now;
2635 GdkPixmap *renderedPixmap = gdk_pixmap_new (NULL, renderInfo->displayWidth,
2636 renderInfo->displayHeight, 24);
2638 // start by running the GDK (fast) rendering test
2639 i = 0;
2640 start = time(NULL);
2641 now = start;
2642 while( now - 30 < start) {
2643 i++;
2644 dprintf("Benchmark(): Starting redraw #%d\n", i);
2645 gerbv_render_to_pixmap_using_gdk (mainProject, renderedPixmap, renderInfo, NULL, NULL);
2646 now = time(NULL);
2647 dprintf("Elapsed time = %ld seconds\n", (long int) (now - start));
2649 g_message("FAST (=GDK) mode benchmark: %d redraws in %ld seconds (%g redraws/second)\n",
2650 i, (long int) (now - start), (double) i / (double)(now - start));
2651 gdk_pixmap_unref(renderedPixmap);
2653 // run the cairo (normal) render mode
2654 i = 0;
2655 start = time(NULL);
2656 now = start;
2657 renderInfo->renderType = GERBV_RENDER_TYPE_CAIRO_NORMAL;
2658 while( now - 30 < start) {
2659 i++;
2660 dprintf("Benchmark(): Starting redraw #%d\n", i);
2661 cairo_surface_t *cSurface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
2662 renderInfo->displayWidth, renderInfo->displayHeight);
2663 cairo_t *cairoTarget = cairo_create (cSurface);
2664 gerbv_render_all_layers_to_cairo_target (mainProject, cairoTarget, renderInfo);
2665 cairo_destroy (cairoTarget);
2666 cairo_surface_destroy (cSurface);
2667 now = time(NULL);
2668 dprintf("Elapsed time = %ld seconds\n", (long int) (now - start));
2670 g_message("NORMAL (=Cairo) mode benchmark: %d redraws in %ld seconds (%g redraws/second)\n",
2671 i, (long int) (now - start), (double) i / (double)(now - start));
2674 /* --------------------------------------------------------------------------- */
2675 void
2676 callbacks_benchmark_clicked (GtkButton *button, gpointer user_data)
2678 // prepare render size and options (canvas size width and height are last 2 variables)
2679 gerbv_render_info_t renderInfo = {1.0, 1.0, 0, 0, 0, 640, 480};
2680 // autoscale the image for now...maybe we don't want to do this in order to
2681 // allow benchmarking of different zoom levels?
2682 gerbv_render_zoom_to_fit_display (mainProject, &renderInfo);
2684 g_message("Full zoom benchmarks\n");
2685 callbacks_support_benchmark (&renderInfo);
2688 g_message("x5 zoom benchmarks\n");
2689 renderInfo.lowerLeftX += (screenRenderInfo.displayWidth /
2690 screenRenderInfo.scaleFactorX) / 3.0;
2691 renderInfo.lowerLeftY += (screenRenderInfo.displayHeight /
2692 screenRenderInfo.scaleFactorY) / 3.0;
2693 renderInfo.scaleFactorX *= 5;
2694 renderInfo.scaleFactorY *= 5;
2695 callbacks_support_benchmark (&renderInfo);
2698 /* --------------------------------------------------------------------------- */
2699 void
2700 callbacks_edit_object_properties_clicked (GtkButton *button, gpointer user_data){
2703 /* --------------------------------------------------------------------------- */
2704 void
2705 callbacks_move_objects_clicked (GtkButton *button, gpointer user_data){
2706 /* for testing, just hard code in some translations here */
2707 gerbv_image_move_selected_objects (screen.selectionInfo.selectedNodeArray, -0.050, 0.050);
2708 callbacks_update_layer_tree();
2709 render_clear_selection_buffer ();
2710 render_refresh_rendered_image_on_screen ();
2713 /* --------------------------------------------------------------------------- */
2714 void
2715 callbacks_reduce_object_area_clicked (GtkButton *button, gpointer user_data){
2716 /* for testing, just hard code in some parameters */
2717 gerbv_image_reduce_area_of_selected_objects (screen.selectionInfo.selectedNodeArray, 0.20, 3, 3, 0.01);
2718 render_clear_selection_buffer ();
2719 render_refresh_rendered_image_on_screen ();
2722 /* --------------------------------------------------------------------------- */
2723 void
2724 callbacks_delete_objects_clicked (GtkButton *button, gpointer user_data){
2725 if (screen.selectionInfo.type == GERBV_SELECTION_EMPTY) {
2726 interface_show_alert_dialog("No object is currently selected",
2727 "Objects must be selected using the pointer tool before they can be deleted.",
2728 FALSE,
2729 NULL);
2730 return;
2733 gint index=callbacks_get_selected_row_index();
2734 if (index < 0)
2735 return;
2737 if (mainProject->check_before_delete == TRUE) {
2738 if (!interface_get_alert_dialog_response(
2739 "Do you want to permanently delete the selected objects?",
2740 "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.",
2741 TRUE,
2742 &(mainProject->check_before_delete)))
2743 return;
2746 gerbv_image_delete_selected_nets (mainProject->file[index]->image,
2747 screen.selectionInfo.selectedNodeArray);
2748 render_refresh_rendered_image_on_screen ();
2749 /* Set layer_dirty flag to TRUE */
2750 mainProject->file[index]->layer_dirty = TRUE;
2751 callbacks_update_layer_tree();
2753 render_clear_selection_buffer ();
2754 callbacks_update_selected_object_message(FALSE);
2757 /* --------------------------------------------------------------------------- */
2758 gboolean
2759 callbacks_drawingarea_configure_event (GtkWidget *widget, GdkEventConfigure *event)
2761 GdkDrawable *drawable = widget->window;
2763 gdk_drawable_get_size (drawable, &screenRenderInfo.displayWidth, &screenRenderInfo.displayHeight);
2765 /* set this up if cairo is compiled, since we may need to switch over to
2766 using the surface at any time */
2767 int x_off=0, y_off=0;
2768 GdkVisual *visual;
2770 if (GDK_IS_WINDOW(widget->window)) {
2771 /* query the window's backbuffer if it has one */
2772 GdkWindow *window = GDK_WINDOW(widget->window);
2773 gdk_window_get_internal_paint_info (window, &drawable, &x_off, &y_off);
2775 visual = gdk_drawable_get_visual (drawable);
2776 if (screen.windowSurface)
2777 cairo_surface_destroy ((cairo_surface_t *)
2778 screen.windowSurface);
2780 #if defined(WIN32) || defined(QUARTZ)
2781 cairo_t *cairoTarget = gdk_cairo_create (GDK_WINDOW(widget->window));
2783 screen.windowSurface = cairo_get_target (cairoTarget);
2784 /* increase surface reference by one so it isn't freed when the cairo_t
2785 is destroyed next */
2786 screen.windowSurface = cairo_surface_reference (screen.windowSurface);
2787 cairo_destroy (cairoTarget);
2788 #else
2789 screen.windowSurface = (gpointer) cairo_xlib_surface_create (GDK_DRAWABLE_XDISPLAY (drawable),
2790 GDK_DRAWABLE_XID (drawable),
2791 GDK_VISUAL_XVISUAL (visual),
2792 screenRenderInfo.displayWidth,
2793 screenRenderInfo.displayHeight);
2794 #endif
2795 /* if this is the first time, go ahead and call autoscale even if we don't
2796 have a model loaded */
2797 if ((screenRenderInfo.scaleFactorX < 0.001)||(screenRenderInfo.scaleFactorY < 0.001)) {
2798 gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
2800 render_refresh_rendered_image_on_screen();
2801 return TRUE;
2804 /* --------------------------------------------------------- */
2805 gboolean
2806 callbacks_drawingarea_expose_event (GtkWidget *widget, GdkEventExpose *event)
2808 if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2809 GdkPixmap *new_pixmap;
2810 GdkGC *gc = gdk_gc_new(widget->window);
2813 * Create a pixmap with default background
2815 new_pixmap = gdk_pixmap_new(widget->window,
2816 widget->allocation.width,
2817 widget->allocation.height,
2818 -1);
2820 gdk_gc_set_foreground(gc, &mainProject->background);
2822 gdk_draw_rectangle(new_pixmap, gc, TRUE,
2823 event->area.x, event->area.y,
2824 event->area.width, event->area.height);
2827 * Copy gerber pixmap onto background if we have one to copy.
2828 * Do translation at the same time.
2830 if (screen.pixmap != NULL) {
2831 gdk_draw_pixmap(new_pixmap,
2832 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
2833 screen.pixmap,
2834 event->area.x - screen.off_x,
2835 event->area.y - screen.off_y,
2836 event->area.x, event->area.y,
2837 event->area.width, event->area.height);
2841 * Draw the whole thing onto screen
2843 gdk_draw_pixmap(widget->window,
2844 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
2845 new_pixmap,
2846 event->area.x, event->area.y,
2847 event->area.x, event->area.y,
2848 event->area.width, event->area.height);
2850 gdk_pixmap_unref(new_pixmap);
2851 gdk_gc_unref(gc);
2854 * Draw Zooming outline if we are in that mode
2856 if (screen.state == IN_ZOOM_OUTLINE) {
2857 render_draw_zoom_outline(screen.centered_outline_zoom);
2859 else if (screen.state == IN_MEASURE) {
2860 render_draw_measure_distance();
2862 if (screen.tool == MEASURE && screen.state != IN_MEASURE) {
2863 render_toggle_measure_line();
2866 return FALSE;
2869 cairo_t *cr;
2870 int width, height;
2871 int x_off=0, y_off=0;
2872 GdkDrawable *drawable = widget->window;
2873 GdkVisual *visual;
2875 if (GDK_IS_WINDOW(widget->window)) {
2876 /* query the window's backbuffer if it has one */
2877 GdkWindow *window = GDK_WINDOW(widget->window);
2878 gdk_window_get_internal_paint_info (window,
2879 &drawable, &x_off, &y_off);
2881 visual = gdk_drawable_get_visual (drawable);
2882 gdk_drawable_get_size (drawable, &width, &height);
2884 #if defined(WIN32) || defined(QUARTZ)
2885 /* FIXME */
2886 cr = gdk_cairo_create (GDK_WINDOW(widget->window));
2887 #else
2888 cairo_surface_t *buffert;
2890 buffert = (gpointer) cairo_xlib_surface_create (GDK_DRAWABLE_XDISPLAY (drawable),
2891 GDK_DRAWABLE_XID (drawable),
2892 GDK_VISUAL_XVISUAL (visual),
2893 event->area.width, event->area.height);
2894 cr = cairo_create (buffert);
2895 #endif
2896 cairo_translate (cr, -event->area.x + screen.off_x, -event->area.y + screen.off_y);
2897 render_project_to_cairo_target (cr);
2898 cairo_destroy (cr);
2899 #if !defined(WIN32) && !defined(QUARTZ)
2900 cairo_surface_destroy (buffert);
2901 #endif
2903 if (screen.tool == MEASURE)
2904 render_toggle_measure_line();
2905 return FALSE;
2908 /* Transforms screen coordinates to board ones */
2909 static void
2910 callbacks_screen2board(gdouble *X, gdouble *Y, gint x, gint y) {
2912 /* make sure we don't divide by zero (which is possible if the gui
2913 isn't displayed yet */
2914 if ((screenRenderInfo.scaleFactorX > 0.001)||(screenRenderInfo.scaleFactorY > 0.001)) {
2915 *X = screenRenderInfo.lowerLeftX + (x / screenRenderInfo.scaleFactorX);
2916 *Y = screenRenderInfo.lowerLeftY + ((screenRenderInfo.displayHeight - y)
2917 / screenRenderInfo.scaleFactorY);
2919 else {
2920 *X = *Y = 0.0;
2924 /* --------------------------------------------------------- */
2925 static void
2926 callbacks_update_statusbar_coordinates (gint x, gint y) {
2927 gdouble X, Y;
2929 callbacks_screen2board(&X, &Y, x, y);
2930 if (screen.unit == GERBV_MILS) {
2931 snprintf(screen.statusbar.coordstr, MAX_COORDLEN,
2932 "(%8.2f, %8.2f)",
2933 COORD2MILS(X), COORD2MILS(Y));
2934 } else if (screen.unit == GERBV_MMS) {
2935 snprintf(screen.statusbar.coordstr, MAX_COORDLEN,
2936 "(%8.3f, %8.3f)",
2937 COORD2MMS(X), COORD2MMS(Y));
2938 } else {
2939 snprintf(screen.statusbar.coordstr, MAX_COORDLEN,
2940 "(%4.5f, %4.5f)",
2941 COORD2MILS(X) / 1000.0, COORD2MILS(Y) / 1000.0);
2943 callbacks_update_statusbar();
2946 void
2947 callbacks_update_selected_object_message (gboolean userTriedToSelect) {
2948 if (screen.tool != POINTER)
2949 return;
2951 gint selectionLength = screen.selectionInfo.selectedNodeArray->len;
2952 if ((selectionLength == 0)&&(userTriedToSelect)) {
2953 /* update status bar message to make sure the user knows
2954 about needing to select the layer */
2955 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2956 "<b>No object selected. Objects can only be selected in the active layer.</b>");
2958 else if (selectionLength == 0) {
2959 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2960 "Click to select objects in the current layer. Middle click and drag to pan.");
2962 else if (selectionLength == 1) {
2963 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2964 "1 object is currently selected");
2966 else {
2967 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2968 "%d objects are currently selected",selectionLength);
2970 callbacks_update_statusbar();
2973 /* --------------------------------------------------------- */
2974 gboolean
2975 callbacks_drawingarea_motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
2977 int x, y;
2978 GdkModifierType state;
2980 if (event->is_hint)
2981 gdk_window_get_pointer (event->window, &x, &y, &state);
2982 else {
2983 x = event->x;
2984 y = event->y;
2985 state = event->state;
2988 switch (screen.state) {
2989 case IN_MOVE: {
2990 if (screen.last_x != 0 || screen.last_y != 0) {
2991 /* Move pixmap to get a snappier feel of movement */
2992 screen.off_x += x - screen.last_x;
2993 screen.off_y += y - screen.last_y;
2995 screenRenderInfo.lowerLeftX -= ((x - screen.last_x) / screenRenderInfo.scaleFactorX);
2996 screenRenderInfo.lowerLeftY += ((y - screen.last_y) / screenRenderInfo.scaleFactorY);
2997 callbacks_force_expose_event_for_screen ();
2998 callbacks_update_scrollbar_positions ();
2999 screen.last_x = x;
3000 screen.last_y = y;
3001 break;
3003 case IN_ZOOM_OUTLINE: {
3004 if (screen.last_x || screen.last_y)
3005 render_draw_zoom_outline(screen.centered_outline_zoom);
3006 screen.last_x = x;
3007 screen.last_y = y;
3008 render_draw_zoom_outline(screen.centered_outline_zoom);
3009 break;
3011 case IN_MEASURE: {
3012 /* clear the previous drawn line by drawing over it */
3013 render_toggle_measure_line();
3014 callbacks_screen2board(&(screen.measure_last_x), &(screen.measure_last_y),
3015 x, y);
3016 /* screen.last_[xy] are updated to move the ruler pointers */
3017 screen.last_x = x;
3018 screen.last_y = y;
3019 /* draw the new line and write the new distance */
3020 render_draw_measure_distance();
3021 break;
3023 case IN_SELECTION_DRAG: {
3024 if (screen.last_x || screen.last_y)
3025 render_draw_selection_box_outline();
3026 screen.last_x = x;
3027 screen.last_y = y;
3028 render_draw_selection_box_outline();
3029 break;
3031 default:
3032 screen.last_x = x;
3033 screen.last_y = y;
3034 break;
3036 callbacks_update_statusbar_coordinates (x, y);
3037 callbacks_update_ruler_pointers ();
3038 return TRUE;
3039 } /* motion_notify_event */
3041 /* --------------------------------------------------------- */
3042 gboolean
3043 callbacks_drawingarea_button_press_event (GtkWidget *widget, GdkEventButton *event)
3045 GdkCursor *cursor;
3047 switch (event->button) {
3048 case 1 :
3049 if (screen.tool == POINTER) {
3050 /* select */
3051 /* selection will only work with cairo, so do nothing if it's
3052 not compiled */
3053 screen.state = IN_SELECTION_DRAG;
3054 screen.start_x = event->x;
3055 screen.start_y = event->y;
3057 else if (screen.tool == PAN) {
3058 /* Plain panning */
3059 screen.state = IN_MOVE;
3060 screen.last_x = event->x;
3061 screen.last_y = event->y;
3063 else if (screen.tool == ZOOM) {
3064 screen.state = IN_ZOOM_OUTLINE;
3065 /* Zoom outline mode initiated */
3066 screen.start_x = event->x;
3067 screen.start_y = event->y;
3068 screen.centered_outline_zoom = event->state;
3070 else if (screen.tool == MEASURE) {
3071 screen.state = IN_MEASURE;
3072 callbacks_screen2board(&(screen.measure_start_x), &(screen.measure_start_y),
3073 event->x, event->y);
3074 screen.measure_last_x = screen.measure_start_x;
3075 screen.measure_last_y = screen.measure_start_y;
3076 /* force an expose event to clear any previous measure lines */
3077 callbacks_force_expose_event_for_screen ();
3079 break;
3080 case 2 :
3081 screen.state = IN_MOVE;
3082 screen.last_x = event->x;
3083 screen.last_y = event->y;
3084 cursor = gdk_cursor_new(GDK_FLEUR);
3085 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
3086 cursor);
3087 gdk_cursor_destroy(cursor);
3088 break;
3089 case 3 :
3090 if (screen.tool == POINTER) {
3091 /* if no items are selected, try and find the item the user
3092 is pointing at */
3093 if (screen.selectionInfo.type == GERBV_SELECTION_EMPTY) {
3094 gint index=callbacks_get_selected_row_index();
3095 if ((index >= 0) &&
3096 (index <= mainProject->last_loaded) &&
3097 (mainProject->file[index]->isVisible)) {
3098 render_fill_selection_buffer_from_mouse_click(event->x,event->y,index,TRUE);
3099 } else {
3100 render_clear_selection_buffer ();
3101 render_refresh_rendered_image_on_screen ();
3104 /* only show the popup if we actually have something selected now */
3105 if (screen.selectionInfo.type != GERBV_SELECTION_EMPTY)
3106 gtk_menu_popup(GTK_MENU(screen.win.drawWindowPopupMenu), NULL, NULL, NULL, NULL,
3107 event->button, event->time);
3108 } else {
3109 /* Zoom outline mode initiated */
3110 screen.state = IN_ZOOM_OUTLINE;
3111 screen.start_x = event->x;
3112 screen.start_y = event->y;
3113 screen.centered_outline_zoom = event->state & GDK_SHIFT_MASK;
3114 cursor = gdk_cursor_new(GDK_SIZING);
3115 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
3116 cursor);
3117 gdk_cursor_destroy(cursor);
3119 break;
3120 case 4 : /* Scroll wheel */
3121 render_zoom_display (ZOOM_IN_CMOUSE, 0, event->x, event->y);
3122 break;
3123 case 5 : /* Scroll wheel */
3124 render_zoom_display (ZOOM_OUT_CMOUSE, 0, event->x, event->y);
3125 break;
3126 default:
3127 break;
3129 callbacks_switch_to_correct_cursor ();
3130 return TRUE;
3133 /* --------------------------------------------------------- */
3134 gboolean
3135 callbacks_drawingarea_button_release_event (GtkWidget *widget, GdkEventButton *event)
3137 if (event->type == GDK_BUTTON_RELEASE) {
3138 if (screen.state == IN_MOVE) {
3139 screen.off_x = 0;
3140 screen.off_y = 0;
3141 render_refresh_rendered_image_on_screen();
3142 callbacks_switch_to_normal_tool_cursor (screen.tool);
3144 else if (screen.state == IN_ZOOM_OUTLINE) {
3145 if ((event->state & GDK_SHIFT_MASK) != 0) {
3146 render_zoom_display (ZOOM_OUT_CMOUSE, 0, event->x, event->y);
3148 /* if the user just clicks without dragging, then simply
3149 zoom in a preset amount */
3150 else if ((abs(screen.start_x - event->x) < 4) &&
3151 (abs(screen.start_y - event->y) < 4)) {
3152 render_zoom_display (ZOOM_IN_CMOUSE, 0, event->x, event->y);
3154 else
3155 render_calculate_zoom_from_outline (widget, event);
3156 callbacks_switch_to_normal_tool_cursor (screen.tool);
3158 else if (screen.state == IN_SELECTION_DRAG) {
3159 /* selection will only work with cairo, so do nothing if it's
3160 not compiled */
3161 gint index=callbacks_get_selected_row_index();
3162 /* determine if this was just a click or a box drag */
3163 if ((index >= 0) &&
3164 (mainProject->file[index]->isVisible)) {
3165 gboolean eraseOldSelection = TRUE;
3167 if ((event->state & GDK_SHIFT_MASK) ||
3168 (event->state & GDK_CONTROL_MASK)) {
3169 eraseOldSelection = FALSE;
3171 if ((fabs((double)(screen.last_x - screen.start_x)) < 5) &&
3172 (fabs((double)(screen.last_y - screen.start_y)) < 5))
3173 render_fill_selection_buffer_from_mouse_click(event->x,event->y,index,eraseOldSelection);
3174 else
3175 render_fill_selection_buffer_from_mouse_drag(event->x,event->y,
3176 screen.start_x,screen.start_y,index,eraseOldSelection);
3177 /* check if anything was selected */
3178 callbacks_update_selected_object_message (TRUE);
3179 } else {
3180 render_clear_selection_buffer ();
3181 render_refresh_rendered_image_on_screen ();
3184 screen.last_x = screen.last_y = 0;
3185 screen.state = NORMAL;
3187 return TRUE;
3188 } /* button_release_event */
3190 /* --------------------------------------------------------- */
3191 gboolean
3192 callbacks_window_key_press_event (GtkWidget *widget, GdkEventKey *event)
3194 switch(event->keyval) {
3195 case GDK_Escape:
3196 if (screen.tool == POINTER) {
3197 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3198 "No objects are currently selected");
3199 callbacks_update_statusbar();
3200 render_clear_selection_buffer ();
3202 break;
3203 default:
3204 break;
3207 /* Escape may be used to abort outline zoom and just plain repaint */
3208 if (event->keyval == GDK_Escape) {
3209 screen.state = NORMAL;
3210 render_refresh_rendered_image_on_screen();
3213 return TRUE;
3214 } /* key_press_event */
3216 /* --------------------------------------------------------- */
3217 gboolean
3218 callbacks_window_key_release_event (GtkWidget *widget, GdkEventKey *event)
3220 return TRUE;
3221 } /* key_release_event */
3223 /* --------------------------------------------------------- */
3224 /* Scroll wheel */
3225 gboolean
3226 callbacks_window_scroll_event(GtkWidget *widget, GdkEventScroll *event)
3228 switch (event->direction) {
3229 case GDK_SCROLL_UP:
3230 render_zoom_display (ZOOM_IN_CMOUSE, 0, event->x, event->y);
3231 break;
3232 case GDK_SCROLL_DOWN:
3233 render_zoom_display (ZOOM_OUT_CMOUSE, 0, event->x, event->y);
3234 break;
3235 case GDK_SCROLL_LEFT:
3236 /* Ignore */
3237 case GDK_SCROLL_RIGHT:
3238 /* Ignore */
3239 default:
3240 return TRUE;
3242 return TRUE;
3243 } /* scroll_event */
3246 /* ------------------------------------------------------------------ */
3247 /** Displays additional information in the statusbar.
3248 The Statusbar is divided into three sections:\n
3249 statusbar.coordstr for coords\n
3250 statusbar.diststr for displaying measured distances or the designator
3251 (right click on a graphically marked and also actively selected part)\n
3252 statusbar.msg for e.g. showing progress of actions*/
3253 void
3254 callbacks_update_statusbar(void)
3256 if ((screen.statusbar.coordstr != NULL)&&(GTK_IS_LABEL(screen.win.statusMessageLeft))) {
3257 gtk_label_set_text(GTK_LABEL(screen.win.statusMessageLeft), screen.statusbar.coordstr);
3259 if ((screen.statusbar.diststr != NULL)&&(GTK_IS_LABEL(screen.win.statusMessageRight))) {
3260 gtk_label_set_markup(GTK_LABEL(screen.win.statusMessageRight), screen.statusbar.diststr);
3264 /* --------------------------------------------------------- */
3265 void
3266 callbacks_update_statusbar_measured_distance (gdouble dx, gdouble dy){
3267 gdouble delta = sqrt(dx*dx + dy*dy);
3269 if (screen.unit == GERBV_MILS) {
3270 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3271 "Measured distance: %8.2f mils (%8.2f x, %8.2f y)",
3272 COORD2MILS(delta), COORD2MILS(dx), COORD2MILS(dy));
3274 else if (screen.unit == GERBV_MMS) {
3275 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3276 "Measured distance: %8.3f mms (%8.3f x, %8.3f y)",
3277 COORD2MMS(delta), COORD2MMS(dx), COORD2MMS(dy));
3279 else {
3280 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3281 "Measured distance: %4.5f inches (%4.5f x, %4.5f y)",
3282 COORD2MILS(delta) / 1000.0, COORD2MILS(dx) / 1000.0,
3283 COORD2MILS(dy) / 1000.0);
3285 callbacks_update_statusbar();
3288 /* --------------------------------------------------------- */
3289 void
3290 callbacks_sidepane_render_type_combo_box_changed (GtkComboBox *widget, gpointer user_data) {
3291 int type = gtk_combo_box_get_active (widget);
3293 dprintf ("%s(): type = %d\n", __FUNCTION__, type);
3295 if (type < 0 || type == screenRenderInfo.renderType)
3296 return;
3298 screenRenderInfo.renderType = type;
3299 callbacks_render_type_changed ();
3302 /* --------------------------------------------------------- */
3303 void
3304 callbacks_viewmenu_rendertype_changed (GtkCheckMenuItem *widget, gpointer user_data) {
3305 gint type = GPOINTER_TO_INT(user_data);
3307 if (type == screenRenderInfo.renderType)
3308 return;
3310 dprintf ("%s(): type = %d\n", __FUNCTION__, type);
3312 screenRenderInfo.renderType = type;
3313 callbacks_render_type_changed ();
3316 /* --------------------------------------------------------- */
3317 void
3318 callbacks_viewmenu_units_changed (GtkCheckMenuItem *widget, gpointer user_data) {
3319 gint unit = GPOINTER_TO_INT(user_data);
3321 if (unit < 0 || unit == screen.unit)
3322 return;
3324 dprintf ("%s(): unit = %d, screen.unit = %d\n", __FUNCTION__, unit, screen.unit);
3326 callbacks_units_changed (unit);
3329 /* --------------------------------------------------------- */
3330 void
3331 callbacks_statusbar_unit_combo_box_changed (GtkComboBox *widget, gpointer user_data) {
3332 int unit = gtk_combo_box_get_active (widget);
3334 if (unit < 0 || unit == screen.unit)
3335 return;
3337 callbacks_units_changed (unit);
3340 /* --------------------------------------------------------- */
3341 void
3342 callbacks_clear_messages_button_clicked (GtkButton *button, gpointer user_data) {
3343 GtkTextBuffer *textbuffer;
3344 GtkTextIter start, end;
3346 textbuffer = gtk_text_view_get_buffer((GtkTextView*)screen.win.messageTextView);
3347 gtk_text_buffer_get_start_iter(textbuffer, &start);
3348 gtk_text_buffer_get_end_iter(textbuffer, &end);
3349 gtk_text_buffer_delete (textbuffer, &start, &end);
3352 /* --------------------------------------------------------- */
3353 void
3354 callbacks_handle_log_messages(const gchar *log_domain, GLogLevelFlags log_level,
3355 const gchar *message, gpointer user_data) {
3356 GtkTextBuffer *textbuffer = NULL;
3357 GtkTextIter iter;
3358 GtkTextTag *tag;
3359 GtkTextMark *StartMark = NULL, *StopMark = NULL;
3360 GtkTextIter StartIter, StopIter;
3362 if (!screen.win.messageTextView)
3363 return;
3365 textbuffer = gtk_text_view_get_buffer((GtkTextView*)screen.win.messageTextView);
3367 /* create a mark for the end of the text. */
3368 gtk_text_buffer_get_end_iter(textbuffer, &iter);
3370 /* get the current end position of the text (it will be the
3371 start of the new text. */
3372 StartMark = gtk_text_buffer_create_mark(textbuffer,
3373 "NewTextStart", &iter, TRUE);
3375 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3376 "blue_foreground");
3377 /* the tag does not exist: create it and let them exist in the tag table.*/
3378 if (tag == NULL) {
3379 tag = gtk_text_buffer_create_tag(textbuffer, "black_foreground",
3380 "foreground", "black", NULL);
3381 tag = gtk_text_buffer_create_tag(textbuffer, "blue_foreground",
3382 "foreground", "blue", NULL);
3383 tag = gtk_text_buffer_create_tag(textbuffer, "red_foreground",
3384 "foreground", "red", NULL);
3385 tag = gtk_text_buffer_create_tag(textbuffer, "darkred_foreground",
3386 "foreground", "darkred", NULL);
3387 tag = gtk_text_buffer_create_tag(textbuffer, "darkblue_foreground",
3388 "foreground", "darkblue", NULL);
3389 tag = gtk_text_buffer_create_tag (textbuffer, "darkgreen_foreground",
3390 "foreground", "darkgreen", NULL);
3391 tag = gtk_text_buffer_create_tag (textbuffer,
3392 "saddlebrown_foreground",
3393 "foreground", "saddlebrown", NULL);
3397 * See rgb.txt for the color names definition
3398 * (on my PC it is on /usr/X11R6/lib/X11/rgb.txt)
3400 switch (log_level & G_LOG_LEVEL_MASK) {
3401 case G_LOG_LEVEL_ERROR:
3402 /* a message of this kind aborts the application calling abort() */
3403 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3404 "red_foreground");
3405 gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
3406 gtk_widget_show(screen.win.sidepane_notebook);
3407 break;
3408 case G_LOG_LEVEL_CRITICAL:
3409 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3410 "red_foreground");
3411 gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
3412 gtk_widget_show(screen.win.sidepane_notebook);
3413 break;
3414 case G_LOG_LEVEL_WARNING:
3415 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3416 "darkred_foreground");
3417 gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
3418 gtk_widget_show(screen.win.sidepane_notebook);
3419 break;
3420 case G_LOG_LEVEL_MESSAGE:
3421 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3422 "darkblue_foreground");
3423 gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
3424 gtk_widget_show(screen.win.sidepane_notebook);
3425 break;
3426 case G_LOG_LEVEL_INFO:
3427 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3428 "darkgreen_foreground");
3429 break;
3430 case G_LOG_LEVEL_DEBUG:
3431 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3432 "saddlebrown_foreground");
3433 break;
3434 default:
3435 tag = gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table(textbuffer),
3436 "black_foreground");
3437 break;
3441 * Fatal aborts application. We will try to get the message out anyhow.
3443 if (log_level & G_LOG_FLAG_FATAL)
3444 fprintf(stderr, "Fatal error : %s\n", message);
3446 gtk_text_buffer_insert(textbuffer, &iter, message, -1);
3448 gtk_text_buffer_get_end_iter(textbuffer, &iter);
3450 StopMark = gtk_text_buffer_create_mark(textbuffer,
3451 "NewTextStop", &iter, TRUE);
3453 gtk_text_buffer_get_iter_at_mark(textbuffer, &StartIter, StartMark);
3454 gtk_text_buffer_get_iter_at_mark(textbuffer, &StopIter, StopMark);
3456 gtk_text_buffer_apply_tag(textbuffer, tag, &StartIter, &StopIter);
3459 /* --------------------------------------------------------- */
3460 void callbacks_force_expose_event_for_screen (void){
3462 GdkRectangle update_rect;
3464 update_rect.x = 0;
3465 update_rect.y = 0;
3466 update_rect.width = screenRenderInfo.displayWidth;
3467 update_rect.height = screenRenderInfo.displayHeight;
3469 /* Calls expose_event */
3470 gdk_window_invalidate_rect (screen.drawing_area->window, &update_rect, FALSE);
3472 /* update other gui things that could have changed */
3473 callbacks_update_ruler_scales ();
3474 callbacks_update_scrollbar_limits ();
3475 callbacks_update_scrollbar_positions ();