add a file merging feature to the GUI menu
[geda-gerbv/spe.git] / src / callbacks.c
blobb8a218725ccba138ee928c25a51b8b6beef19ccb
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 #ifndef WIN32
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 #else
72 #include <cairo-xlib.h>
73 #endif
76 #define dprintf if(DEBUG) printf
78 /* This default extension should really not be changed, but if it absolutely
79 * must change, the ../win32/gerbv.nsi.in *must* be changed to reflect that.
80 * Just grep for the extension (gvp) and change it in two places in that file.
82 #define GERBV_PROJECT_FILE_NAME "Gerbv Project"
83 #define GERBV_PROJECT_FILE_EXT ".gvp"
84 #define GERBV_PROJECT_FILE_PAT "*.gvp"
86 #define SAVE_PROJECT 0
87 #define SAVE_AS_PROJECT 1
88 #define OPEN_PROJECT 2
89 # define _(String) (String)
91 /**Global variable to keep track of what's happening on the screen.
92 Declared extern in gerbv_screen.h
94 extern gerbv_screen_t screen;
95 extern gerbv_render_info_t screenRenderInfo;
98 /* These are the names of the valid apertures. These
99 * values are used in several places in this file.
100 * Please keep this in sync with the gerbv_aperture_type_t
101 * enum defined in gerbv.h */
102 char *ap_names[] = {"NONE",
103 "CIRCLE",
104 "RECTANGLE",
105 "OVAL", /* an ovular (obround) aperture */
106 "POLYGON", /* a polygon aperture */
107 "MACRO", /* a RS274X macro */
108 "MACRO_CIRCLE", /* a RS274X circle macro */
109 "MACRO_OUTLINE", /* a RS274X outline macro */
110 "MACRO_POLYGON", /* a RS274X polygon macro */
111 "MACRO_MOIRE", /* a RS274X moire macro */
112 "MACRO_THERMAL", /* a RS274X thermal macro */
113 "MACRO_LINE20", /* a RS274X line (code 20) macro */
114 "MACRO_LINE21", /* a RS274X line (code 21) macro */
115 "MACRO_LINE22" /* a RS274X line (code 22) macro */
118 static gint callbacks_get_selected_row_index (void);
119 static void callbacks_units_changed (gerbv_gui_unit_t unit);
120 static void callbacks_update_statusbar_coordinates (gint x, gint y);
121 static void callbacks_update_ruler_scales (void);
122 static void callbacks_render_type_changed (void);
123 static void show_no_layers_warning (void);
125 /* --------------------------------------------------------- */
127 static void show_no_layers_warning (void) {
128 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
129 "<b>No layers are currently loaded. A layer must be loaded first.</b>");
130 callbacks_update_statusbar();
133 /* --------------------------------------------------------- */
134 GtkWidget *
135 callbacks_generate_alert_dialog (gchar *primaryText, gchar *secondaryText){
136 GtkWidget *dialog, *label;
138 dialog = gtk_dialog_new_with_buttons (primaryText,
139 (GtkWindow *)screen.win.topLevelWindow,
140 GTK_DIALOG_DESTROY_WITH_PARENT,
141 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
142 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
143 NULL);
144 label = gtk_label_new (secondaryText);
145 /* Add the label, and show everything we've added to the dialog. */
146 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
147 label);
148 gtk_widget_show_all (dialog);
149 return dialog;
152 /* --------------------------------------------------------- */
154 * The file -> new menu item was selected. Create new
155 * project.
158 void
159 callbacks_new_activate (GtkMenuItem *menuitem, gpointer user_data)
161 if (mainProject->last_loaded >= 0) {
162 if (!interface_get_alert_dialog_response (
163 "Do you want to close any open layers and start a new project?",
164 "Starting a new project will cause all currently open layers to be closed. Any unsaved changes will be lost.",
165 FALSE,
166 NULL))
167 return;
169 /* Unload all layers and then clear layer window */
170 gerbv_unload_all_layers (mainProject);
171 callbacks_update_layer_tree ();
172 render_clear_selection_buffer ();
174 /* Destroy project info */
175 if (mainProject->project) {
176 g_free(mainProject->project);
177 mainProject->project = NULL;
179 render_refresh_rendered_image_on_screen();
183 /* --------------------------------------------------------- */
185 * The file -> open menu item was selected. Open a
186 * project file.
189 void
190 callbacks_open_project_activate (GtkMenuItem *menuitem,
191 gpointer user_data)
193 gchar *filename=NULL;
194 GtkFileFilter * filter;
196 if (mainProject->last_loaded >= 0) {
197 if (!interface_get_alert_dialog_response (
198 "Do you want to close any open layers and load an existing project?",
199 "Loading a project will cause all currently open layers to be closed. Any unsaved changes will be lost.",
200 FALSE,
201 NULL))
202 return;
205 screen.win.gerber =
206 gtk_file_chooser_dialog_new ("Open project file...",
207 NULL,
208 GTK_FILE_CHOOSER_ACTION_OPEN,
209 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
210 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
211 NULL);
212 gtk_file_chooser_set_current_folder ((GtkFileChooser *) screen.win.gerber,
213 mainProject->path);
215 filter = gtk_file_filter_new();
216 gtk_file_filter_set_name(filter, GERBV_PROJECT_FILE_NAME);
217 gtk_file_filter_add_pattern(filter, GERBV_PROJECT_FILE_PAT);
218 gtk_file_chooser_add_filter ((GtkFileChooser *) screen.win.gerber,
219 filter);
221 filter = gtk_file_filter_new();
222 gtk_file_filter_set_name(filter, "All");
223 gtk_file_filter_add_pattern(filter, "*");
224 gtk_file_chooser_add_filter ((GtkFileChooser *) screen.win.gerber,
225 filter);
227 gtk_widget_show (screen.win.gerber);
228 if (gtk_dialog_run ((GtkDialog*)screen.win.gerber) == GTK_RESPONSE_ACCEPT) {
229 filename =
230 gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (screen.win.gerber));
231 /* update the last folder */
232 g_free (mainProject->path);
233 mainProject->path = gtk_file_chooser_get_current_folder ((GtkFileChooser *) screen.win.gerber);
235 gtk_widget_destroy (screen.win.gerber);
237 if (filename) {
238 gerbv_unload_all_layers (mainProject);
239 main_open_project_from_filename (mainProject, filename);
241 gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
242 render_refresh_rendered_image_on_screen();
243 callbacks_update_layer_tree();
245 return;
249 /* --------------------------------------------------------- */
251 * The file -> open layer menu item was selected. Open a
252 * layer (or layers) from a file.
255 void
256 callbacks_open_layer_activate (GtkMenuItem *menuitem,
257 gpointer user_data)
259 GSList *filenames=NULL;
260 GSList *filename=NULL;
262 screen.win.gerber =
263 gtk_file_chooser_dialog_new ("Open Gerber, drill, or pick & place file(s)...",
264 NULL,
265 GTK_FILE_CHOOSER_ACTION_OPEN,
266 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
267 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
268 NULL);
270 gtk_file_chooser_set_select_multiple((GtkFileChooser *) screen.win.gerber, TRUE);
271 gtk_file_chooser_set_current_folder ((GtkFileChooser *) screen.win.gerber,
272 mainProject->path);
273 gtk_widget_show (screen.win.gerber);
274 if (gtk_dialog_run ((GtkDialog*)screen.win.gerber) == GTK_RESPONSE_ACCEPT) {
275 filenames =
276 gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER (screen.win.gerber));
277 /* update the last folder */
278 g_free (mainProject->path);
279 mainProject->path = gtk_file_chooser_get_current_folder ((GtkFileChooser *) screen.win.gerber);
281 gtk_widget_destroy (screen.win.gerber);
283 /* Now try to open all gerbers specified */
284 for (filename=filenames; filename; filename=filename->next) {
285 gerbv_open_layer_from_filename (mainProject, filename->data);
287 g_slist_free(filenames);
289 gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
290 render_refresh_rendered_image_on_screen();
291 callbacks_update_layer_tree();
293 return;
296 /* --------------------------------------------------------- */
297 void
298 callbacks_revert_activate (GtkMenuItem *menuitem,
299 gpointer user_data)
301 gerbv_revert_all_files (mainProject);
302 render_clear_selection_buffer();
303 callbacks_update_selected_object_message(FALSE);
304 render_refresh_rendered_image_on_screen();
305 callbacks_update_layer_tree();
308 /* --------------------------------------------------------- */
309 void
310 callbacks_save_project_activate (GtkMenuItem *menuitem,
311 gpointer user_data)
313 if (mainProject->project)
314 main_save_project_from_filename (mainProject, mainProject->project);
315 else
316 callbacks_generic_save_activate (menuitem, (gpointer) CALLBACKS_SAVE_PROJECT_AS);
317 callbacks_update_layer_tree();
318 return;
321 /* --------------------------------------------------------- */
322 void
323 callbacks_save_layer_activate (GtkMenuItem *menuitem,
324 gpointer user_data)
326 /* first figure out which layer in the layer side menu is selected */
327 gint index=callbacks_get_selected_row_index();
329 /* Now save that layer */
330 if (index >= 0) {
331 if (!gerbv_save_layer_from_index (mainProject, index, mainProject->file[index]->fullPathname)) {
332 interface_show_alert_dialog("Gerbv cannot export this file type",
333 NULL,
334 FALSE,
335 NULL);
336 mainProject->file[index]->layer_dirty = FALSE;
337 callbacks_update_layer_tree();
338 return;
341 callbacks_update_layer_tree();
342 return;
344 struct l_image_info {
345 gerbv_image_t *image;
346 gerbv_user_transformation_t *transform;
348 /* --------------------------------------------------------- */
349 /**Go through each file and look at visibility, then type.
350 Make sure we have at least 2 files.
353 gerbv_image_t *merge_images (int type)
355 gint i, filecount, img;
356 /* struct l_image_info *images; */
357 gerbv_image_t *out;
358 struct l_image_info {
359 gerbv_image_t *image;
360 gerbv_user_transformation_t *transform;
361 }*images;
364 images=(struct l_image_info *)g_new0(struct l_image_info,1);
365 out=NULL;
366 switch(type){
367 case CALLBACKS_SAVE_FILE_DRILLM:
368 type=GERBV_LAYERTYPE_DRILL;
369 break;
370 case CALLBACKS_SAVE_FILE_RS274XM:
371 type=GERBV_LAYERTYPE_RS274X;
372 break;
373 default:
374 GERB_MESSAGE("Unknown Layer type for merge\n");
375 goto err;
377 dprintf("Looking for matching files\n");
378 for (i=img=filecount=0;i<mainProject->max_files;++i){
379 if (mainProject->file[i] && mainProject->file[i]->isVisible &&
380 (mainProject->file[i]->image->layertype == type) ) {
381 ++filecount;
382 dprintf("Adding '%s'\n",mainProject->file[i]->name);
383 images[img].image=mainProject->file[i]->image;
384 /* printf("Adding transform\n"); */
385 images[img++].transform=&mainProject->file[i]->transform;
386 /* printf("Realloc\n"); */
387 images=(struct l_image_info *)g_renew(struct l_image_info, images,img+1);
389 /* printf("Done with add\n"); */
391 if(2>filecount){
392 GERB_MESSAGE ("Not Enough Files of same type to merge\n");
393 goto err;
395 dprintf("Now merging files\n");
396 for (i=0;i<img;++i){
397 gerbv_user_transformation_t *thisTransform;
398 gerbv_user_transformation_t identityTransform = {0,0,1,1,0,FALSE,FALSE,FALSE};
399 thisTransform=images[i].transform;
400 if (NULL == thisTransform )
401 thisTransform = &identityTransform;
402 if(0 == i)
403 out = gerbv_image_duplicate_image (images[i].image, thisTransform);
404 else
405 gerbv_image_copy_image(images[i].image,thisTransform,out);
407 err:
408 g_free(images);
409 return out;
411 /* --------------------------------------------------------- */
412 void
413 callbacks_generic_save_activate (GtkMenuItem *menuitem,
414 gpointer user_data)
416 gchar *filename=NULL;
417 gint processType = GPOINTER_TO_INT (user_data);
418 gchar *windowTitle=NULL;
419 GtkFileFilter * filter;
421 if (processType == CALLBACKS_SAVE_PROJECT_AS)
422 windowTitle = g_strdup ("Save project as...");
423 else if (processType == CALLBACKS_SAVE_FILE_PS)
424 windowTitle = g_strdup ("Export PS file as...");
425 else if (processType == CALLBACKS_SAVE_FILE_PDF)
426 windowTitle = g_strdup ("Export PDF file as...");
427 else if (processType == CALLBACKS_SAVE_FILE_SVG)
428 windowTitle = g_strdup ("Export SVG file as...");
429 else if (processType == CALLBACKS_SAVE_FILE_PNG)
430 windowTitle = g_strdup ("Export PNG file as...");
431 else if (processType == CALLBACKS_SAVE_FILE_RS274X)
432 windowTitle = g_strdup ("Export RS-274X file as...");
433 else if (processType == CALLBACKS_SAVE_FILE_DRILL)
434 windowTitle = g_strdup ("Export Excellon drill file as...");
435 else if (processType == CALLBACKS_SAVE_FILE_RS274XM)
436 windowTitle = g_strdup ("Export RS-274Xm file as...");
437 else if (processType == CALLBACKS_SAVE_FILE_DRILLM)
438 windowTitle = g_strdup ("Export Excellon drillm file as...");
439 else if (processType == CALLBACKS_SAVE_LAYER_AS)
440 windowTitle = g_strdup ("Save layer as...");
442 screen.win.gerber =
443 gtk_file_chooser_dialog_new (windowTitle, NULL,
444 GTK_FILE_CHOOSER_ACTION_SAVE,
445 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
446 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
447 NULL);
448 g_free (windowTitle);
450 /* if we're saving or exporting a layer, start off in the location of the
451 loaded file */
452 if (processType != CALLBACKS_SAVE_PROJECT_AS) {
453 gint index=callbacks_get_selected_row_index();
454 if (index >= 0) {
455 gchar *dirName = g_path_get_dirname (mainProject->file[index]->fullPathname);
456 gtk_file_chooser_set_current_folder ((GtkFileChooser *) screen.win.gerber,
457 dirName);
458 g_free (dirName);
462 if (processType == CALLBACKS_SAVE_PROJECT_AS) {
463 filter = gtk_file_filter_new();
464 gtk_file_filter_set_name(filter, GERBV_PROJECT_FILE_NAME);
465 gtk_file_filter_add_pattern(filter, GERBV_PROJECT_FILE_PAT);
466 gtk_file_chooser_add_filter ((GtkFileChooser *) screen.win.gerber,
467 filter);
469 filter = gtk_file_filter_new();
470 gtk_file_filter_set_name(filter, "All");
471 gtk_file_filter_add_pattern(filter, "*");
472 gtk_file_chooser_add_filter ((GtkFileChooser *) screen.win.gerber,
473 filter);
475 gtk_file_chooser_set_current_name ((GtkFileChooser *) screen.win.gerber,
476 "untitled" GERBV_PROJECT_FILE_EXT );
479 gtk_widget_show (screen.win.gerber);
480 if (gtk_dialog_run ((GtkDialog*)screen.win.gerber) == GTK_RESPONSE_ACCEPT) {
481 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (screen.win.gerber));
483 gtk_widget_destroy (screen.win.gerber);
485 if (filename) {
486 if (processType == CALLBACKS_SAVE_PROJECT_AS) {
487 main_save_as_project_from_filename (mainProject, filename);
488 rename_main_window(filename, NULL);
490 else if (processType == CALLBACKS_SAVE_FILE_PS)
491 gerbv_export_postscript_file_from_project_autoscaled (mainProject, filename);
492 else if (processType == CALLBACKS_SAVE_FILE_PDF)
493 gerbv_export_pdf_file_from_project_autoscaled (mainProject, filename);
494 else if (processType == CALLBACKS_SAVE_FILE_SVG)
495 gerbv_export_svg_file_from_project_autoscaled (mainProject, filename);
496 else if (processType == CALLBACKS_SAVE_FILE_PNG)
497 gerbv_export_png_file_from_project_autoscaled (mainProject,
498 screenRenderInfo.displayWidth, screenRenderInfo.displayHeight,
499 filename);
500 else if (processType == CALLBACKS_SAVE_LAYER_AS) {
501 gint index=callbacks_get_selected_row_index();
503 gerbv_save_layer_from_index (mainProject, index, filename);
504 /* rename the file path in the index, so future saves will reference the new file path */
505 g_free (mainProject->file[index]->fullPathname);
506 mainProject->file[index]->fullPathname = g_strdup (filename);
507 g_free (mainProject->file[index]->name);
508 mainProject->file[index]->name = g_path_get_basename (filename);
510 else if (processType == CALLBACKS_SAVE_FILE_RS274X) {
511 gint index=callbacks_get_selected_row_index();
513 gerbv_export_rs274x_file_from_image (filename, mainProject->file[index]->image,
514 &mainProject->file[index]->transform);
516 else if (processType == CALLBACKS_SAVE_FILE_DRILL) {
517 gint index=callbacks_get_selected_row_index();
519 gerbv_export_drill_file_from_image (filename, mainProject->file[index]->image,
520 &mainProject->file[index]->transform);
521 } /**create new image.... */
522 else if (processType == CALLBACKS_SAVE_FILE_RS274XM) {
523 gerbv_image_t *image;
524 gerbv_user_transformation_t t = {0,0,1,1,0,FALSE,FALSE,FALSE};
525 if(NULL != (image=merge_images(processType)) ){
526 /*printf("Preparing to export merge\n"); */
527 gerbv_export_rs274x_file_from_image (filename, image, &t);
528 gerbv_destroy_image(image);
529 GERB_MESSAGE ("Merged visible gerber layers and placed in '%s'\n",filename);
532 else if (processType == CALLBACKS_SAVE_FILE_DRILLM) {
533 gerbv_image_t *image;
534 gerbv_user_transformation_t t = {0,0,1,1,0,FALSE,FALSE,FALSE};
535 if(NULL != (image=merge_images(processType)) ){
536 gerbv_export_drill_file_from_image (filename, image,&t);
537 gerbv_destroy_image(image);
538 GERB_MESSAGE ("Merged visible drill layers and placed in '%s'\n",filename);
542 g_free (filename);
543 callbacks_update_layer_tree();
544 return;
547 /* --------------------------------------------------------- */
548 #if GTK_CHECK_VERSION(2,10,0)
550 static void
551 callbacks_begin_print (GtkPrintOperation *operation, GtkPrintContext *context,
552 gpointer user_data) {
553 gtk_print_operation_set_n_pages (operation, 1);
557 /* --------------------------------------------------------- */
558 static void
559 callbacks_print_render_page (GtkPrintOperation *operation,
560 GtkPrintContext *context,
561 gint page_nr,
562 gpointer user_data)
564 GtkPrintSettings *pSettings = gtk_print_operation_get_print_settings (operation);
565 gerbv_render_info_t renderInfo = {1.0, 1.0, 0, 0, 3,
566 (gint) gtk_print_context_get_width (context),
567 (gint) gtk_print_context_get_height (context)};
568 cairo_t *cr;
569 int i;
571 /* have to assume x and y resolutions are the same for now, since we
572 don't support differing scales in the gerb_render_info_t struct yet */
573 gdouble xres = gtk_print_context_get_dpi_x (context);
574 gdouble yres = gtk_print_context_get_dpi_y (context);
575 gdouble scalePercentage = gtk_print_settings_get_scale (pSettings);
576 renderInfo.scaleFactorX = scalePercentage / 100 * xres;
577 renderInfo.scaleFactorY = scalePercentage / 100 * yres;
579 gerbv_render_translate_to_fit_display (mainProject, &renderInfo);
580 cr = gtk_print_context_get_cairo_context (context);
581 for(i = 0; i <= mainProject->last_loaded; i++) {
582 if (mainProject->file[i] && mainProject->file[i]->isVisible) {
583 //cairo_push_group (cr);
584 gerbv_render_layer_to_cairo_target (cr, mainProject->file[i], &renderInfo);
585 //cairo_pop_group_to_source (cr);
586 //cairo_paint_with_alpha (cr, screen.file[i]->alpha);
591 /* --------------------------------------------------------- */
592 void
593 callbacks_print_activate (GtkMenuItem *menuitem, gpointer user_data)
595 GtkPrintOperation *print;
596 GtkPrintOperationResult res;
598 print = gtk_print_operation_new ();
600 g_signal_connect (print, "begin_print", G_CALLBACK (callbacks_begin_print), NULL);
601 g_signal_connect (print, "draw_page", G_CALLBACK (callbacks_print_render_page), NULL);
603 //GtkPrintSettings *pSettings = gtk_print_operation_get_print_settings (print);
605 res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
606 (GtkWindow *) screen.win.topLevelWindow , NULL);
608 g_object_unref (print);
610 #endif /* GTK_CHECK_VERSION(2,10,0) */
612 /* --------------------------------------------------------- */
613 void
614 callbacks_fullscreen_toggled (GtkMenuItem *menuitem, gpointer user_data)
616 //struct GtkWindow *win = (struct GtkWindow *)(screen.win.topLevelWindow);
617 GdkWindowState state = gdk_window_get_state (gtk_widget_get_window(screen.win.topLevelWindow));
618 if(state & GDK_WINDOW_STATE_FULLSCREEN)
619 gtk_window_unfullscreen (GTK_WINDOW(screen.win.topLevelWindow));
620 else
621 gtk_window_fullscreen (GTK_WINDOW(screen.win.topLevelWindow));
624 /* --------------------------------------------------------- */
625 void
626 callbacks_show_toolbar_toggled (GtkMenuItem *menuitem, gpointer user_data)
628 gtk_widget_set_visible (user_data, GTK_CHECK_MENU_ITEM(menuitem)->active);
631 /* --------------------------------------------------------- */
632 void
633 callbacks_show_sidepane_toggled (GtkMenuItem *menuitem, gpointer user_data)
635 gtk_widget_set_visible (user_data, GTK_CHECK_MENU_ITEM(menuitem)->active);
638 /* --------------------------------------------------------- */
639 /** View/"Toggle visibility layer X" or Current layer/"Toggle visibility" menu item was activated.
640 * Set the isVisible flag on file X and update the treeview and rendering.
642 void
643 callbacks_toggle_layer_visibility_activate (GtkMenuItem *menuitem, gpointer user_data)
645 int i = GPOINTER_TO_INT(user_data);
646 if (i < 0)
647 i = callbacks_get_selected_row_index ();
649 if (0 <= i && i <= mainProject->last_loaded) {
650 mainProject->file[i]->isVisible = !mainProject->file[i]->isVisible;
651 /* clear any selected items so they don't show after the layer is hidden */
652 render_clear_selection_buffer();
654 callbacks_update_layer_tree ();
655 if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
656 render_refresh_rendered_image_on_screen();
658 else {
659 render_recreate_composite_surface (screen.drawing_area);
660 callbacks_force_expose_event_for_screen ();
665 /* --------------------------------------------------------- */
666 void
667 callbacks_zoom_in_activate (GtkMenuItem *menuitem,
668 gpointer user_data)
670 render_zoom_display (ZOOM_IN, 0, 0, 0);
673 /* --------------------------------------------------------- */
674 void
675 callbacks_zoom_out_activate (GtkMenuItem *menuitem,
676 gpointer user_data)
678 render_zoom_display (ZOOM_OUT, 0, 0, 0);
681 /* --------------------------------------------------------- */
682 void
683 callbacks_fit_to_window_activate (GtkMenuItem *menuitem,
684 gpointer user_data)
686 gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
687 render_refresh_rendered_image_on_screen();
691 /* --------------------------------------------------------- */
693 * The analyze -> analyze Gerbers menu item was selected.
694 * Compile statistics on all open Gerber layers and then display
695 * them.
698 void
699 callbacks_analyze_active_gerbers_activate(GtkMenuItem *menuitem,
700 gpointer user_data)
702 gerbv_stats_t *stats_report;
703 GString *G_report_string = g_string_new(NULL);
704 GString *D_report_string = g_string_new(NULL);
705 GString *M_report_string = g_string_new(NULL);
706 GString *misc_report_string = g_string_new(NULL);
707 GString *general_report_string = g_string_new(NULL);
708 GString *error_report_string = g_string_new(NULL);
709 gerbv_error_list_t *my_error_list;
710 gchar *error_level = NULL;
711 GString *aperture_def_report_string = g_string_new(NULL);
712 GString *aperture_use_report_string = g_string_new(NULL);
713 gerbv_aperture_list_t *my_aperture_list;
714 int idx;
715 int aperture_count = 0;
717 /* First get a report of stats & errors accumulated from all layers */
718 stats_report = generate_gerber_analysis();
720 /* General info report */
721 g_string_printf(general_report_string,
722 "General information\n");
723 g_string_append_printf(general_report_string,
724 " Active layer count = %d\n",
725 stats_report->layer_count);
726 g_string_append_printf(general_report_string,
727 "\n\n%-45s %-10s\n",
728 "Files processed",
729 "Layer number");
730 for (idx = 0; idx <= mainProject->last_loaded; idx++) {
731 if (mainProject->file[idx] &&
732 mainProject->file[idx]->isVisible &&
733 (mainProject->file[idx]->image->layertype == GERBV_LAYERTYPE_RS274X) ) {
734 g_string_append_printf(general_report_string,
735 " %-45s %-10d\n", mainProject->file[idx]->name, idx+1);
739 /* Error report (goes into general report tab) */
740 if (stats_report->layer_count == 0) {
741 g_string_printf(error_report_string,
742 "\n\nNo Gerber files active (visible)!\n");
743 } else if (stats_report->error_list->error_text == NULL) {
744 g_string_printf(error_report_string,
745 "\n\nNo errors found in active Gerber file(s)!\n");
746 } else {
747 g_string_printf(error_report_string,
748 "\n\nErrors found in active Gerber file(s):\n");
749 for(my_error_list = stats_report->error_list;
750 my_error_list != NULL;
751 my_error_list = my_error_list->next) {
752 switch(my_error_list->type) {
753 case GERBV_MESSAGE_FATAL: /* We should never get this one since the
754 * program should terminate first.... */
755 error_level = g_strdup_printf("FATAL: ");
756 break;
757 case GERBV_MESSAGE_ERROR:
758 error_level = g_strdup_printf("ERROR: ");
759 break;
760 case GERBV_MESSAGE_WARNING:
761 error_level = g_strdup_printf("WARNING: ");
762 break;
763 case GERBV_MESSAGE_NOTE:
764 error_level = g_strdup_printf("NOTE: ");
765 break;
767 g_string_append_printf(error_report_string,
768 " Layer %d: %s %s",
769 my_error_list->layer,
770 error_level,
771 my_error_list->error_text );
772 g_free(error_level);
777 g_string_append_printf(general_report_string,
778 "%s",
779 error_report_string->str);
780 g_string_free(error_report_string, TRUE);
782 /* Now compile stats related to reading G codes */
783 g_string_printf(G_report_string,
784 "G code statistics (all active layers)\n");
785 g_string_append_printf(G_report_string,
786 "<code> = <number of incidences>\n");
787 g_string_append_printf(G_report_string,
788 "G0 = %-6d (%s)\n",
789 stats_report->G0,
790 "Move");
791 g_string_append_printf(G_report_string,
792 "G1 = %-6d (%s)\n",
793 stats_report->G1,
794 "1X linear interpolation");
795 g_string_append_printf(G_report_string,
796 "G2 = %-6d (%s)\n",
797 stats_report->G2,
798 "CW interpolation");
799 g_string_append_printf(G_report_string,
800 "G3 = %-6d (%s)\n",
801 stats_report->G3,
802 "CCW interpolation");
803 g_string_append_printf(G_report_string,
804 "G4 = %-6d (%s)\n",
805 stats_report->G4,
806 "Comment/ignore block");
807 g_string_append_printf(G_report_string,
808 "G10 = %-6d (%s)\n",
809 stats_report->G10,
810 "10X linear interpolation");
811 g_string_append_printf(G_report_string,
812 "G11 = %-6d (%s)\n",
813 stats_report->G11,
814 "0.1X linear interpolation");
815 g_string_append_printf(G_report_string,
816 "G12 = %-6d (%s)\n",
817 stats_report->G12,
818 "0.01X linear interpolation");
819 g_string_append_printf(G_report_string,
820 "G36 = %-6d (%s)\n",
821 stats_report->G36,
822 "Poly fill on");
823 g_string_append_printf(G_report_string,
824 "G37 = %-6d (%s)\n",
825 stats_report->G37,
826 "Poly fill off");
827 g_string_append_printf(G_report_string,
828 "G54 = %-6d (%s)\n",
829 stats_report->G54,
830 "Tool prepare");
831 g_string_append_printf(G_report_string,
832 "G55 = %-6d (%s)\n",
833 stats_report->G55,
834 "Flash prepare");
835 g_string_append_printf(G_report_string,
836 "G70 = %-6d (%s)\n",
837 stats_report->G70,
838 "Units = inches");
839 g_string_append_printf(G_report_string,
840 "G71 = %-6d (%s)\n",
841 stats_report->G71,
842 "Units = mm");
843 g_string_append_printf(G_report_string,
844 "G74 = %-6d (%s)\n",
845 stats_report->G74,
846 "Disable 360 circ. interpolation");
847 g_string_append_printf(G_report_string,
848 "G75 = %-6d (%s)\n",
849 stats_report->G75,
850 "Enable 360 circ. interpolation");
851 g_string_append_printf(G_report_string,
852 "G90 = %-6d (%s)\n",
853 stats_report->G90,
854 "Absolute units");
855 g_string_append_printf(G_report_string,
856 "G91 = %-6d (%s)\n",
857 stats_report->G91,
858 "Incremental units");
859 g_string_append_printf(G_report_string,
860 "Unknown G codes = %d\n",
861 stats_report->G_unknown);
864 g_string_printf(D_report_string, "D code statistics (all active layers)\n");
865 g_string_append_printf(D_report_string,
866 "<code> = <number of incidences>\n");
867 g_string_append_printf(D_report_string,
868 "D1 = %-6d (%s)\n",
869 stats_report->D1,
870 "Exposure on");
871 g_string_append_printf(D_report_string,
872 "D2 = %-6d (%s)\n",
873 stats_report->D2,
874 "Exposure off");
875 g_string_append_printf(D_report_string,
876 "D3 = %-6d (%s)\n",
877 stats_report->D3,
878 "Flash aperture");
879 g_string_append_printf(D_report_string,
880 "Undefined D codes = %d\n",
881 stats_report->D_unknown);
882 g_string_append_printf(D_report_string,
883 "D code Errors = %d\n",
884 stats_report->D_error);
887 g_string_printf(M_report_string, "M code statistics (all active layers)\n");
888 g_string_append_printf(M_report_string,
889 "<code> = <number of incidences>\n");
890 g_string_append_printf(M_report_string,
891 "M0 = %-6d (%s)\n",
892 stats_report->M0,
893 "Program start");
894 g_string_append_printf(M_report_string,
895 "M1 = %-6d (%s)\n",
896 stats_report->M1,
897 "Program stop");
898 g_string_append_printf(M_report_string,
899 "M2 = %-6d (%s)\n",
900 stats_report->M2,
901 "Program end");
902 g_string_append_printf(M_report_string,
903 "Unknown M codes = %d\n",
904 stats_report->M_unknown);
907 g_string_printf(misc_report_string, "Misc code statistics (all active layers)\n");
908 g_string_append_printf(misc_report_string,
909 "<code> = <number of incidences>\n");
910 g_string_append_printf(misc_report_string,
911 "X = %d\n", stats_report->X);
912 g_string_append_printf(misc_report_string,
913 "Y = %d\n", stats_report->Y);
914 g_string_append_printf(misc_report_string,
915 "I = %d\n", stats_report->I);
916 g_string_append_printf(misc_report_string,
917 "J = %d\n", stats_report->J);
918 g_string_append_printf(misc_report_string,
919 "* = %d\n", stats_report->star);
920 g_string_append_printf(misc_report_string,
921 "Unknown codes = %d\n",
922 stats_report->unknown);
924 /* Report apertures defined in input files. */
926 if (stats_report->aperture_list->number == -1) {
927 g_string_printf(aperture_def_report_string,
928 "No aperture definitions found in Gerber file(s)!\n");
929 } else {
930 g_string_printf(aperture_def_report_string,
931 "Apertures defined in Gerber file(s) (by layer)\n");
932 g_string_append_printf(aperture_def_report_string,
933 " %-6s %-8s %12s %8s %8s %8s\n",
934 "Layer",
935 "D code",
936 "Aperture",
937 "Param[0]",
938 "Param[1]",
939 "Param[2]"
941 for(my_aperture_list = stats_report->aperture_list;
942 my_aperture_list != NULL;
943 my_aperture_list = my_aperture_list->next) {
945 g_string_append_printf(aperture_def_report_string,
946 " %-6d D%-4d%13s %8.3f %8.3f %8.3f\n",
947 my_aperture_list->layer,
948 my_aperture_list->number,
949 ap_names[my_aperture_list->type],
950 my_aperture_list->parameter[0],
951 my_aperture_list->parameter[1],
952 my_aperture_list->parameter[2]
957 /* Report apertures usage count in input files. */
958 if (stats_report->D_code_list->number == -1) {
959 g_string_printf(aperture_use_report_string,
960 "No apertures used in Gerber file(s)!\n");
961 } else {
963 /* Now add list of user-defined D codes (apertures) */
965 g_string_printf(aperture_use_report_string,
966 "Apertures used in Gerber file(s) (all active layers)\n");
967 g_string_append_printf(aperture_use_report_string,
968 "<aperture code> = <number of uses>\n");
969 for (my_aperture_list = stats_report->D_code_list;
970 my_aperture_list != NULL;
971 my_aperture_list = my_aperture_list->next) {
973 g_string_append_printf(aperture_use_report_string,
974 " D%d = %-6d\n",
975 my_aperture_list->number,
976 my_aperture_list->count
978 aperture_count += my_aperture_list->count;
981 g_string_append_printf(aperture_use_report_string,
982 "\nTotal number of aperture uses: %d\n", aperture_count);
985 /* Create top level dialog window for report */
986 GtkWidget *analyze_active_gerbers;
987 analyze_active_gerbers = gtk_dialog_new_with_buttons("Gerber codes report",
988 NULL,
989 GTK_DIALOG_DESTROY_WITH_PARENT,
990 GTK_STOCK_OK,
991 GTK_RESPONSE_ACCEPT,
992 NULL);
993 gtk_container_set_border_width (GTK_CONTAINER (analyze_active_gerbers), 5);
995 gtk_dialog_set_default_response (GTK_DIALOG(analyze_active_gerbers),
996 GTK_RESPONSE_ACCEPT);
997 g_signal_connect (G_OBJECT(analyze_active_gerbers),
998 "response",
999 G_CALLBACK (gtk_widget_destroy),
1000 GTK_WIDGET(analyze_active_gerbers));
1002 /* Use fixed width font for all reports */
1003 PangoFontDescription *font =
1004 pango_font_description_from_string ("monospace");
1006 /* Create GtkLabel to hold general report text */
1007 GtkWidget *general_report_label = gtk_label_new (general_report_string->str);
1008 g_string_free (general_report_string, TRUE);
1009 gtk_misc_set_alignment(GTK_MISC(general_report_label), 0, 0);
1010 gtk_misc_set_padding(GTK_MISC(general_report_label), 13, 13);
1011 gtk_label_set_selectable(GTK_LABEL(general_report_label), TRUE);
1012 gtk_widget_modify_font (GTK_WIDGET(general_report_label),
1013 font);
1014 /* Put general report text into scrolled window */
1015 GtkWidget *general_code_report_window = gtk_scrolled_window_new (NULL, NULL);
1016 /* This throws a warning. Must find different approach.... */
1017 gtk_widget_set_size_request(GTK_WIDGET(general_code_report_window),
1018 200,
1019 300);
1020 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(general_code_report_window),
1021 GTK_WIDGET(general_report_label));
1023 /* Create GtkLabel to hold G code text */
1024 GtkWidget *G_report_label = gtk_label_new (G_report_string->str);
1025 g_string_free (G_report_string, TRUE);
1026 gtk_misc_set_alignment(GTK_MISC(G_report_label), 0, 0);
1027 gtk_misc_set_padding(GTK_MISC(G_report_label), 13, 13);
1028 gtk_label_set_selectable(GTK_LABEL(G_report_label), TRUE);
1029 gtk_widget_modify_font (GTK_WIDGET(G_report_label),
1030 font);
1032 /* Create GtkLabel to hold D code text */
1033 GtkWidget *D_report_label = gtk_label_new (D_report_string->str);
1034 g_string_free (D_report_string, TRUE);
1035 gtk_misc_set_alignment(GTK_MISC(D_report_label), 0, 0);
1036 gtk_misc_set_padding(GTK_MISC(D_report_label), 13, 13);
1037 gtk_label_set_selectable(GTK_LABEL(D_report_label), TRUE);
1038 gtk_widget_modify_font (GTK_WIDGET(D_report_label),
1039 font);
1041 /* Create GtkLabel to hold M code text */
1042 GtkWidget *M_report_label = gtk_label_new (M_report_string->str);
1043 g_string_free (M_report_string, TRUE);
1044 gtk_misc_set_alignment(GTK_MISC(M_report_label), 0, 0);
1045 gtk_misc_set_padding(GTK_MISC(M_report_label), 13, 13);
1046 gtk_label_set_selectable(GTK_LABEL(M_report_label), TRUE);
1047 gtk_widget_modify_font (GTK_WIDGET(M_report_label),
1048 font);
1050 /* Create GtkLabel to hold misc code text */
1051 GtkWidget *misc_report_label = gtk_label_new (misc_report_string->str);
1052 g_string_free (misc_report_string, TRUE);
1053 gtk_misc_set_alignment(GTK_MISC(misc_report_label), 0, 0);
1054 gtk_misc_set_padding(GTK_MISC(misc_report_label), 13, 13);
1055 gtk_label_set_selectable(GTK_LABEL(misc_report_label), TRUE);
1056 gtk_widget_modify_font (GTK_WIDGET(misc_report_label),
1057 font);
1059 /* Create GtkLabel to hold aperture defintion text */
1060 GtkWidget *aperture_def_report_label = gtk_label_new (aperture_def_report_string->str);
1061 g_string_free (aperture_def_report_string, TRUE);
1062 gtk_misc_set_alignment(GTK_MISC(aperture_def_report_label), 0, 0);
1063 gtk_misc_set_padding(GTK_MISC(aperture_def_report_label), 13, 13);
1064 gtk_label_set_selectable(GTK_LABEL(aperture_def_report_label), TRUE);
1065 gtk_widget_modify_font (GTK_WIDGET(aperture_def_report_label),
1066 font);
1067 /* Put aperture definintion text into scrolled window */
1068 GtkWidget *aperture_def_report_window = gtk_scrolled_window_new (NULL, NULL);
1069 /* This throws a warning. Must find different approach.... */
1070 gtk_widget_set_size_request(GTK_WIDGET(aperture_def_report_window),
1071 200,
1072 300);
1073 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(aperture_def_report_window),
1074 GTK_WIDGET(aperture_def_report_label));
1076 /* Create GtkLabel to hold aperture use text */
1077 GtkWidget *aperture_use_report_label = gtk_label_new (aperture_use_report_string->str);
1078 g_string_free (aperture_use_report_string, TRUE);
1079 gtk_misc_set_alignment(GTK_MISC(aperture_use_report_label), 0, 0);
1080 gtk_misc_set_padding(GTK_MISC(aperture_use_report_label), 13, 13);
1081 gtk_label_set_selectable(GTK_LABEL(aperture_use_report_label), TRUE);
1082 gtk_widget_modify_font (GTK_WIDGET(aperture_use_report_label),
1083 font);
1084 /* Put aperture definintion text into scrolled window */
1085 GtkWidget *aperture_use_report_window = gtk_scrolled_window_new (NULL, NULL);
1086 /* This throws a warning. Must find different approach.... */
1087 gtk_widget_set_size_request(GTK_WIDGET(aperture_use_report_window),
1088 200,
1089 300);
1090 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(aperture_use_report_window),
1091 GTK_WIDGET(aperture_use_report_label));
1093 /* Create tabbed notebook widget and add report label widgets. */
1094 GtkWidget *notebook = gtk_notebook_new();
1096 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1097 GTK_WIDGET(general_code_report_window),
1098 gtk_label_new("General"));
1100 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1101 GTK_WIDGET(G_report_label),
1102 gtk_label_new("G codes"));
1104 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1105 GTK_WIDGET(D_report_label),
1106 gtk_label_new("D codes"));
1108 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1109 GTK_WIDGET(M_report_label),
1110 gtk_label_new("M codes"));
1112 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1113 GTK_WIDGET(misc_report_label),
1114 gtk_label_new("Misc. codes"));
1116 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1117 GTK_WIDGET(aperture_def_report_window),
1118 gtk_label_new("Aperture definitions"));
1120 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1121 GTK_WIDGET(aperture_use_report_window),
1122 gtk_label_new("Aperture usage"));
1125 /* Now put notebook into dialog window and show the whole thing */
1126 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(analyze_active_gerbers)->vbox),
1127 GTK_WIDGET(notebook));
1129 gtk_widget_show_all(analyze_active_gerbers);
1131 /* free the stats report */
1132 gerbv_stats_destroy (stats_report);
1133 return;
1137 /* --------------------------------------------------------- */
1139 * The analyze -> analyze drill file menu item was selected.
1140 * Complie statistics on all open drill layers and then display
1141 * them.
1144 void
1145 callbacks_analyze_active_drill_activate(GtkMenuItem *menuitem,
1146 gpointer user_data)
1148 gerbv_drill_stats_t *stats_report;
1149 GString *G_report_string = g_string_new(NULL);
1150 GString *M_report_string = g_string_new(NULL);
1151 GString *misc_report_string = g_string_new(NULL);
1152 gerbv_drill_list_t *my_drill_list;
1153 GString *drill_report_string = g_string_new(NULL);
1154 GString *general_report_string = g_string_new(NULL);
1155 GString *error_report_string = g_string_new(NULL);
1156 gerbv_error_list_t *my_error_list;
1157 gchar *error_level = NULL;
1158 int idx;
1160 stats_report = (gerbv_drill_stats_t *) generate_drill_analysis();
1162 /* General and error window strings */
1163 g_string_printf(general_report_string, "General information\n");
1164 g_string_append_printf(general_report_string,
1165 " Active layer count = %d\n",
1166 stats_report->layer_count);
1168 g_string_append_printf(general_report_string,
1169 "\n\nFiles processed:\n");
1170 for (idx = mainProject->last_loaded; idx >= 0; idx--) {
1171 if (mainProject->file[idx] &&
1172 mainProject->file[idx]->isVisible &&
1173 (mainProject->file[idx]->image->layertype == GERBV_LAYERTYPE_DRILL) ) {
1174 g_string_append_printf(general_report_string,
1175 " %s\n",
1176 mainProject->file[idx]->name);
1181 if (stats_report->layer_count == 0) {
1182 g_string_printf(error_report_string, "\n\nNo drill files active (visible)!\n");
1183 } else if (stats_report->error_list->error_text == NULL) {
1184 g_string_printf(error_report_string,
1185 "\n\nNo errors found in active drill file(s)!\n");
1186 } else {
1187 g_string_printf(error_report_string,
1188 "\n\nErrors found in active drill file(s):\n");
1189 for(my_error_list = stats_report->error_list;
1190 my_error_list != NULL;
1191 my_error_list = my_error_list->next) {
1192 switch(my_error_list->type) {
1193 case GERBV_MESSAGE_FATAL: /* We should never get this one since the
1194 * program should terminate first.... */
1195 error_level = g_strdup_printf("FATAL: ");
1196 break;
1197 case GERBV_MESSAGE_ERROR:
1198 error_level = g_strdup_printf("ERROR: ");
1199 break;
1200 case GERBV_MESSAGE_WARNING:
1201 error_level = g_strdup_printf("WARNING: ");
1202 break;
1203 case GERBV_MESSAGE_NOTE:
1204 error_level = g_strdup_printf("NOTE: ");
1205 break;
1207 g_string_append_printf(error_report_string,
1208 " Layer %d: %s %s",
1209 my_error_list->layer,
1210 error_level,
1211 my_error_list->error_text);
1215 g_string_append_printf(general_report_string,
1216 "%s", error_report_string->str);
1217 g_string_free(error_report_string, TRUE);
1220 /* G code window strings */
1221 g_string_printf(G_report_string, "G code statistics (all active layers)\n");
1222 g_string_append_printf(G_report_string,
1223 "<code> = <number of incidences>\n");
1224 g_string_append_printf(G_report_string,
1225 "G00 = %-6d (%s)\n",
1226 stats_report->G00,
1227 "Rout mode");
1228 g_string_append_printf(G_report_string,
1229 "G01 = %-6d (%s)\n",
1230 stats_report->G01,
1231 "1X linear interpolation");
1232 g_string_append_printf(G_report_string,
1233 "G02 = %-6d (%s)\n",
1234 stats_report->G02,
1235 "CW interpolation");
1236 g_string_append_printf(G_report_string,
1237 "G03 = %-6d (%s)\n",
1238 stats_report->G03,
1239 "CCW interpolation");
1240 g_string_append_printf(G_report_string,
1241 "G04 = %-6d (%s)\n",
1242 stats_report->G04,
1243 "Variable dwell");
1244 g_string_append_printf(G_report_string,
1245 "G05 = %-6d (%s)\n",
1246 stats_report->G05,
1247 "Drill mode");
1248 g_string_append_printf(G_report_string,
1249 "G90 = %-6d (%s)\n",
1250 stats_report->G90,
1251 "Absolute units");
1252 g_string_append_printf(G_report_string,
1253 "G91 = %-6d (%s)\n",
1254 stats_report->G91,
1255 "Incremental units");
1256 g_string_append_printf(G_report_string,
1257 "G93 = %-6d (%s)\n",
1258 stats_report->G93,
1259 "Zero set");
1260 g_string_append_printf(G_report_string,
1261 "Unknown G codes = %d\n",
1262 stats_report->G_unknown);
1264 /* M code window strings */
1265 g_string_printf(M_report_string, "M code statistics (all active layers)\n");
1266 g_string_append_printf(M_report_string,
1267 "<code> = <number of incidences>\n");
1268 g_string_append_printf(M_report_string,
1269 "M00 = %-6d (%s)\n",
1270 stats_report->M00,
1271 "End of program");
1272 g_string_append_printf(M_report_string,
1273 "M01 = %-6d (%s)\n",
1274 stats_report->M01,
1275 "End of pattern");
1276 g_string_append_printf(M_report_string,
1277 "M18 = %-6d (%s)\n",
1278 stats_report->M18,
1279 "Tool tip check");
1280 g_string_append_printf(M_report_string,
1281 "M25 = %-6d (%s)\n",
1282 stats_report->M25,
1283 "Begin pattern");
1284 g_string_append_printf(M_report_string,
1285 "M30 = %-6d (%s)\n",
1286 stats_report->M30,
1287 "End program rewind");
1288 g_string_append_printf(M_report_string,
1289 "M31 = %-6d (%s)\n",
1290 stats_report->M31,
1291 "Begin pattern");
1292 g_string_append_printf(M_report_string,
1293 "M45 = %-6d (%s)\n",
1294 stats_report->M45,
1295 "Long message");
1296 g_string_append_printf(M_report_string,
1297 "M47 = %-6d (%s)\n",
1298 stats_report->M47,
1299 "Operator message");
1300 g_string_append_printf(M_report_string,
1301 "M48 = %-6d (%s)\n",
1302 stats_report->M48,
1303 "Begin program header");
1304 g_string_append_printf(M_report_string,
1305 "M71 = %-6d (%s)\n",
1306 stats_report->M71,
1307 "Metric units");
1308 g_string_append_printf(M_report_string,
1309 "M72 = %-6d (%s)\n",
1310 stats_report->M72,
1311 "English units");
1312 g_string_append_printf(M_report_string,
1313 "M95 = %-6d (%s)\n",
1314 stats_report->M95,
1315 "End program header");
1316 g_string_append_printf(M_report_string,
1317 "M97 = %-6d (%s)\n",
1318 stats_report->M97,
1319 "Canned text");
1320 g_string_append_printf(M_report_string,
1321 "M98 = %-6d (%s)\n",
1322 stats_report->M98,
1323 "Canned text");
1324 g_string_append_printf(M_report_string,
1325 "Unknown M codes = %d\n",
1326 stats_report->M_unknown);
1329 /* misc report strings */
1330 g_string_printf(misc_report_string, "Misc code statistics (all active layers)\n");
1331 g_string_append_printf(misc_report_string,
1332 "<code> = <number of incidences>\n");
1333 g_string_append_printf(misc_report_string,
1334 "comments = %d\n",
1335 stats_report->comment);
1336 g_string_append_printf(misc_report_string,
1337 "Unknown codes = %d\n",
1338 stats_report->unknown);
1340 g_string_append_printf(misc_report_string,
1341 "R = %-6d (%s)\n",
1342 stats_report->R,
1343 "Repeat hole");
1345 if (stats_report->detect != NULL ) {
1346 g_string_append_printf(misc_report_string,
1347 "\n%s\n",
1348 stats_report->detect);
1350 /* drill report window strings */
1351 g_string_printf(drill_report_string, "Drills used (all active layers)\n");
1352 g_string_append_printf(drill_report_string, "%10s %8s %8s %8s\n",
1353 "Drill no.", "Dia.", "Units", "Count");
1354 for(my_drill_list = stats_report->drill_list;
1355 my_drill_list != NULL;
1356 my_drill_list = my_drill_list->next) {
1357 if (my_drill_list->drill_num == -1) break; /* No drill list */
1358 g_string_append_printf(drill_report_string,
1359 "%10d %8.3f %8s %8d\n",
1360 my_drill_list->drill_num,
1361 my_drill_list->drill_size,
1362 my_drill_list->drill_unit,
1363 my_drill_list->drill_count);
1366 g_string_append_printf(drill_report_string, "Total drill count %d\n",
1367 stats_report->total_count);
1369 /* Use fixed width font for all reports */
1370 PangoFontDescription *font =
1371 pango_font_description_from_string ("monospace");
1373 /* Create top level dialog window for report */
1374 GtkWidget *analyze_active_drill;
1375 analyze_active_drill = gtk_dialog_new_with_buttons("Drill file codes report",
1376 NULL,
1377 GTK_DIALOG_DESTROY_WITH_PARENT,
1378 GTK_STOCK_OK,
1379 GTK_RESPONSE_ACCEPT,
1380 NULL);
1381 gtk_container_set_border_width (GTK_CONTAINER (analyze_active_drill), 5);
1382 gtk_dialog_set_default_response (GTK_DIALOG(analyze_active_drill),
1383 GTK_RESPONSE_ACCEPT);
1384 g_signal_connect (G_OBJECT(analyze_active_drill),
1385 "response",
1386 G_CALLBACK (gtk_widget_destroy),
1387 GTK_WIDGET(analyze_active_drill));
1389 /* Create GtkLabel to hold general report text */
1390 GtkWidget *general_report_label = gtk_label_new (general_report_string->str);
1391 g_string_free(general_report_string, TRUE);
1392 gtk_misc_set_alignment(GTK_MISC(general_report_label), 0, 0);
1393 gtk_misc_set_padding(GTK_MISC(general_report_label), 13, 13);
1394 gtk_label_set_selectable(GTK_LABEL(general_report_label), TRUE);
1395 gtk_widget_modify_font (GTK_WIDGET(general_report_label),
1396 font);
1398 /* Create GtkLabel to hold G code text */
1399 GtkWidget *G_report_label = gtk_label_new (G_report_string->str);
1400 g_string_free(G_report_string, TRUE);
1401 gtk_misc_set_alignment(GTK_MISC(G_report_label), 0, 0);
1402 gtk_misc_set_padding(GTK_MISC(G_report_label), 13, 13);
1403 gtk_label_set_selectable(GTK_LABEL(G_report_label), TRUE);
1404 gtk_widget_modify_font (GTK_WIDGET(G_report_label),
1405 font);
1407 /* Create GtkLabel to hold M code text */
1408 GtkWidget *M_report_label = gtk_label_new (M_report_string->str);
1409 g_string_free(M_report_string, TRUE);
1410 gtk_misc_set_alignment(GTK_MISC(M_report_label), 0, 0);
1411 gtk_misc_set_padding(GTK_MISC(M_report_label), 13, 13);
1412 gtk_label_set_selectable(GTK_LABEL(M_report_label), TRUE);
1413 gtk_widget_modify_font (GTK_WIDGET(M_report_label),
1414 font);
1416 /* Create GtkLabel to hold misc code text */
1417 GtkWidget *misc_report_label = gtk_label_new (misc_report_string->str);
1418 g_string_free(misc_report_string, TRUE);
1419 gtk_misc_set_alignment(GTK_MISC(misc_report_label), 0, 0);
1420 gtk_misc_set_padding(GTK_MISC(misc_report_label), 13, 13);
1421 gtk_label_set_selectable(GTK_LABEL(misc_report_label), TRUE);
1422 gtk_widget_modify_font (GTK_WIDGET(misc_report_label),
1423 font);
1425 /* Create GtkLabel to hold drills used text */
1426 GtkWidget *drill_report_label = gtk_label_new (drill_report_string->str);
1427 g_string_free(drill_report_string, TRUE);
1428 gtk_misc_set_alignment(GTK_MISC(drill_report_label), 0, 0);
1429 gtk_misc_set_padding(GTK_MISC(drill_report_label), 13, 13);
1430 gtk_label_set_selectable(GTK_LABEL(drill_report_label), TRUE);
1431 gtk_widget_modify_font (GTK_WIDGET(drill_report_label),
1432 font);
1434 /* Create tabbed notebook widget and add report label widgets. */
1435 GtkWidget *notebook = gtk_notebook_new();
1437 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1438 GTK_WIDGET(general_report_label),
1439 gtk_label_new("General"));
1441 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1442 GTK_WIDGET(G_report_label),
1443 gtk_label_new("G codes"));
1445 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1446 GTK_WIDGET(M_report_label),
1447 gtk_label_new("M codes"));
1449 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1450 GTK_WIDGET(misc_report_label),
1451 gtk_label_new("Misc. codes"));
1453 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1454 GTK_WIDGET(drill_report_label),
1455 gtk_label_new("Drills used"));
1457 /* Now put notebook into dialog window and show the whole thing */
1458 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(analyze_active_drill)->vbox),
1459 GTK_WIDGET(notebook));
1460 gtk_widget_show_all(analyze_active_drill);
1461 gerbv_drill_stats_destroy (stats_report);
1462 return;
1465 /* --------------------------------------------------------- */
1466 void
1467 callbacks_control_gerber_options_activate (GtkMenuItem *menuitem,
1468 gpointer user_data)
1473 /* --------------------------------------------------------- */
1474 void
1475 callbacks_online_manual_activate (GtkMenuItem *menuitem,
1476 gpointer user_data)
1481 /* --------------------------------------------------------- */
1483 * The file -> quit menu item was selected or
1484 * the user requested the main window to be closed by other means.
1485 * Check that all changes have been saved, and then quit.
1488 gboolean
1489 callbacks_quit_activate (GtkMenuItem *menuitem,
1490 gpointer user_data)
1492 gboolean layers_dirty = FALSE;
1493 gint idx;
1495 for (idx = 0; idx<=mainProject->last_loaded; idx++) {
1496 if (mainProject->file[idx] == NULL) break;
1497 layers_dirty = layers_dirty || mainProject->file[idx]->layer_dirty;
1500 if (layers_dirty &&
1501 !interface_get_alert_dialog_response(
1502 "Do you want to close all open layers and quit the program?",
1503 "Quitting the program will cause any unsaved changes to be lost.",
1504 FALSE,
1505 NULL)) {
1506 return TRUE; // stop propagation of the delete_event.
1507 // this would destroy the gui but not return from the gtk event loop.
1509 gerbv_unload_all_layers (mainProject);
1510 gtk_main_quit();
1511 return FALSE; // more or less... meaningless :)
1514 /* --------------------------------------------------------- */
1516 * The help -> about menu item was selected.
1517 * Show the about dialog.
1520 void
1521 callbacks_about_activate (GtkMenuItem *menuitem,
1522 gpointer user_data)
1524 GtkWidget *aboutdialog1;
1525 /* TRANSLATORS: Replace this string with your names, one name per line. */
1526 /* gchar *translators = _("translator-credits"); */
1528 gchar *string = g_strdup_printf ( "gerbv -- a Gerber (RS-274/X) viewer.\n\n"
1529 "This is gerbv version %s\n"
1530 "Compiled on %s at %s\n"
1531 "\n"
1532 "gerbv is part of the gEDA Project.\n"
1533 "\n"
1534 "For more information see:\n"
1535 " gerbv homepage: http://gerbv.gpleda.org/\n"
1536 " gEDA homepage: http://gpleda.org/\n"
1537 " gEDA Wiki: http://geda.seul.org/wiki/",
1538 VERSION, __DATE__, __TIME__);
1539 #if GTK_CHECK_VERSION(2,6,0)
1540 gchar *license = g_strdup_printf("gerbv -- a Gerber (RS-274/X) viewer.\n\n"
1541 "Copyright (C) 2000-2007 Stefan Petersen\n\n"
1542 "This program is free software: you can redistribute it and/or modify\n"
1543 "it under the terms of the GNU General Public License as published by\n"
1544 "the Free Software Foundation, either version 2 of the License, or\n"
1545 "(at your option) any later version.\n\n"
1546 "This program is distributed in the hope that it will be useful,\n"
1547 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1548 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1549 "GNU General Public License for more details.\n\n"
1550 "You should have received a copy of the GNU General Public License\n"
1551 "along with this program. If not, see <http://www.gnu.org/licenses/>.");
1552 #include "authors.c"
1554 aboutdialog1 = gtk_about_dialog_new ();
1555 gtk_container_set_border_width (GTK_CONTAINER (aboutdialog1), 5);
1556 gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (aboutdialog1), VERSION);
1557 gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (aboutdialog1), _("Gerbv"));
1559 /* gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG (aboutdialog1), translators); */
1560 gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (aboutdialog1), string);
1561 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG (aboutdialog1), license);
1563 /* The authors.c file is autogenerated at build time */
1564 gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG (aboutdialog1), authors_string_array);
1565 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG (aboutdialog1), "http://gerbv.gpleda.org/");
1567 g_signal_connect (G_OBJECT(aboutdialog1),"response",
1568 G_CALLBACK (gtk_widget_destroy), GTK_WIDGET(aboutdialog1));
1570 g_free (string);
1571 g_free (license);
1572 #else
1573 aboutdialog1 = gtk_message_dialog_new ( GTK_WINDOW (screen.win.topLevelWindow),
1574 GTK_DIALOG_DESTROY_WITH_PARENT,
1575 GTK_MESSAGE_INFO,
1576 GTK_BUTTONS_CLOSE,
1577 string
1580 gtk_window_set_title ( GTK_WINDOW (aboutdialog1), _("About Gerbv"));
1582 /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
1583 g_signal_connect_swapped (aboutdialog1, "response",
1584 G_CALLBACK (gtk_widget_destroy),
1585 aboutdialog1);
1586 g_free (string);
1587 #endif
1589 gtk_widget_show_all(GTK_WIDGET(aboutdialog1));
1593 /* --------------------------------------------------------- */
1595 * The help -> bugs menu item was selected.
1596 * Show the known bugs window
1599 void
1600 callbacks_bugs_activate (GtkMenuItem *menuitem,
1601 gpointer user_data)
1603 int i;
1604 #include "bugs.c"
1606 /* Create the top level dialog widget with an OK button */
1607 GtkWidget *bugs_dialog = gtk_dialog_new_with_buttons("Known bugs in gerbv",
1608 NULL,
1609 GTK_DIALOG_DESTROY_WITH_PARENT,
1610 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1611 NULL);
1612 gtk_container_set_border_width (GTK_CONTAINER (bugs_dialog), 5);
1613 gtk_dialog_set_default_response (GTK_DIALOG(bugs_dialog),
1614 GTK_RESPONSE_ACCEPT);
1615 g_signal_connect (G_OBJECT(bugs_dialog), "response",
1616 G_CALLBACK (gtk_widget_destroy), GTK_WIDGET(bugs_dialog));
1618 /* First create single bugs_string from bugs_string_array */
1619 GString *bugs_string = g_string_new(NULL);
1620 for (i=0; bugs_string_array[i] != NULL; i++) {
1621 g_string_append_printf(bugs_string,
1622 "%s\n",
1623 bugs_string_array[i]);
1626 /* Create GtkLabel to hold text */
1627 GtkWidget *bugs_label = gtk_label_new (bugs_string->str);
1628 g_string_free(bugs_string, TRUE);
1629 gtk_misc_set_alignment(GTK_MISC(bugs_label), 0, 0);
1630 gtk_misc_set_padding(GTK_MISC(bugs_label), 13, 13);
1632 /* Put text into scrolled window */
1633 GtkWidget *bugs_window = gtk_scrolled_window_new (NULL, NULL);
1634 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(bugs_window),
1635 GTK_WIDGET(bugs_label));
1636 gtk_widget_set_size_request(GTK_WIDGET(bugs_window), 600, 300);
1637 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(bugs_dialog)->vbox),
1638 GTK_WIDGET(bugs_window));
1640 gtk_widget_show_all(GTK_WIDGET(bugs_dialog));
1641 gtk_dialog_run(GTK_DIALOG(bugs_dialog));
1645 /* --------------------------------------------------------- */
1646 gdouble callbacks_calculate_actual_distance (gdouble inputDimension) {
1647 gdouble returnValue = 0.0;
1649 if (screen.unit == GERBV_MILS) {
1650 returnValue = COORD2MILS(inputDimension);
1651 } else if (screen.unit == GERBV_MMS) {
1652 returnValue = COORD2MMS(inputDimension);
1653 } else {
1654 returnValue = COORD2MILS(inputDimension)/1000;
1656 return returnValue;
1659 /* --------------------------------------------------------- */
1660 void callbacks_update_ruler_pointers (void) {
1661 double xPosition, yPosition;
1662 xPosition = screenRenderInfo.lowerLeftX + (screen.last_x / screenRenderInfo.scaleFactorX);
1663 yPosition = screenRenderInfo.lowerLeftY + ((screenRenderInfo.displayHeight - screen.last_y) / screenRenderInfo.scaleFactorY);
1665 if (!((screen.unit == GERBV_MILS) && ((screenRenderInfo.scaleFactorX < 80)||(screenRenderInfo.scaleFactorY < 80)))) {
1666 xPosition = callbacks_calculate_actual_distance (xPosition);
1667 yPosition = callbacks_calculate_actual_distance (yPosition);
1669 g_object_set (G_OBJECT (screen.win.hRuler), "position", xPosition, NULL);
1670 g_object_set (G_OBJECT (screen.win.vRuler), "position", yPosition, NULL);
1673 /* --------------------------------------------------------- */
1674 static void
1675 callbacks_render_type_changed () {
1676 static gboolean isChanging = FALSE;
1677 if (isChanging)
1678 return;
1680 isChanging = TRUE;
1681 gerbv_render_types_t type = screenRenderInfo.renderType;
1682 GtkCheckMenuItem *check_item = screen.win.menu_view_render_group[type];
1683 dprintf ("%s(): type = %d, check_item = %p\n", __FUNCTION__, type, check_item);
1684 gtk_check_menu_item_set_active (check_item, TRUE);
1685 gtk_combo_box_set_active (screen.win.sidepaneRenderComboBox, type);
1687 render_refresh_rendered_image_on_screen();
1688 isChanging = FALSE;
1691 /* --------------------------------------------------------- */
1692 static void
1693 callbacks_units_changed (gerbv_gui_unit_t unit) {
1694 static gboolean isChanging = FALSE;
1696 if (isChanging)
1697 return;
1699 isChanging = TRUE;
1700 screen.unit = unit;
1702 if (unit == GERBV_MILS){
1703 gtk_combo_box_set_active (GTK_COMBO_BOX (screen.win.statusUnitComboBox), GERBV_MILS);
1704 gtk_check_menu_item_set_active (screen.win.menu_view_unit_group[GERBV_MILS], TRUE);
1705 } else if (unit == GERBV_MMS){
1706 gtk_combo_box_set_active (GTK_COMBO_BOX (screen.win.statusUnitComboBox), GERBV_MMS);
1707 gtk_check_menu_item_set_active (screen.win.menu_view_unit_group[GERBV_MMS], TRUE);
1708 } else {
1709 gtk_combo_box_set_active (GTK_COMBO_BOX (screen.win.statusUnitComboBox), GERBV_INS);
1710 gtk_check_menu_item_set_active (screen.win.menu_view_unit_group[GERBV_INS], TRUE);
1713 callbacks_update_ruler_scales ();
1714 callbacks_update_statusbar_coordinates (screen.last_x, screen.last_y);
1716 if (screen.tool == MEASURE)
1717 callbacks_update_statusbar_measured_distance (screen.win.lastMeasuredX, screen.win.lastMeasuredY);
1719 isChanging = FALSE;
1722 /* --------------------------------------------------------- */
1723 static void
1724 callbacks_update_ruler_scales (void) {
1725 double xStart, xEnd, yStart, yEnd;
1727 xStart = screenRenderInfo.lowerLeftX;
1728 yStart = screenRenderInfo.lowerLeftY;
1729 xEnd = screenRenderInfo.lowerLeftX + (screenRenderInfo.displayWidth / screenRenderInfo.scaleFactorX);
1730 yEnd = screenRenderInfo.lowerLeftY + (screenRenderInfo.displayHeight / screenRenderInfo.scaleFactorY);
1731 /* mils can get super crowded with large boards, but inches are too
1732 large for most boards. So, we leave mils in for now and just switch
1733 to inches if the scale factor gets too small */
1734 if (!((screen.unit == GERBV_MILS) && ((screenRenderInfo.scaleFactorX < 80)||(screenRenderInfo.scaleFactorY < 80)))) {
1735 xStart = callbacks_calculate_actual_distance (xStart);
1736 xEnd = callbacks_calculate_actual_distance (xEnd);
1737 yStart = callbacks_calculate_actual_distance (yStart);
1738 yEnd = callbacks_calculate_actual_distance (yEnd);
1740 /* make sure the widgets actually exist before setting (in case this gets
1741 called before everything is realized */
1742 if (screen.win.hRuler)
1743 gtk_ruler_set_range (GTK_RULER (screen.win.hRuler), xStart, xEnd, 0, xEnd - xStart);
1744 /* reverse y min and max, since the ruler starts at the top */
1745 if (screen.win.vRuler)
1746 gtk_ruler_set_range (GTK_RULER (screen.win.vRuler), yEnd, yStart, 0, yEnd - yStart);
1749 /* --------------------------------------------------------- */
1750 void callbacks_update_scrollbar_limits (void){
1751 gerbv_render_info_t tempRenderInfo = {0, 0, 0, 0, 3, screenRenderInfo.displayWidth,
1752 screenRenderInfo.displayHeight};
1754 GtkAdjustment *hAdjust = (GtkAdjustment *)screen.win.hAdjustment;
1755 GtkAdjustment *vAdjust = (GtkAdjustment *)screen.win.vAdjustment;
1756 gerbv_render_zoom_to_fit_display (mainProject, &tempRenderInfo);
1757 hAdjust->lower = tempRenderInfo.lowerLeftX;
1758 hAdjust->page_increment = hAdjust->page_size;
1759 hAdjust->step_increment = hAdjust->page_size / 10.0;
1760 vAdjust->lower = tempRenderInfo.lowerLeftY;
1761 vAdjust->page_increment = vAdjust->page_size;
1762 vAdjust->step_increment = vAdjust->page_size / 10.0;
1763 hAdjust->upper = tempRenderInfo.lowerLeftX + (tempRenderInfo.displayWidth / tempRenderInfo.scaleFactorX);
1764 hAdjust->page_size = screenRenderInfo.displayWidth / screenRenderInfo.scaleFactorX;
1765 vAdjust->upper = tempRenderInfo.lowerLeftY + (tempRenderInfo.displayHeight / tempRenderInfo.scaleFactorY);
1766 vAdjust->page_size = screenRenderInfo.displayHeight / screenRenderInfo.scaleFactorY;
1767 callbacks_update_scrollbar_positions ();
1770 /* --------------------------------------------------------- */
1771 void callbacks_update_scrollbar_positions (void){
1772 gdouble positionX,positionY;
1774 positionX = screenRenderInfo.lowerLeftX;
1775 if (positionX < ((GtkAdjustment *)screen.win.hAdjustment)->lower)
1776 positionX = ((GtkAdjustment *)screen.win.hAdjustment)->lower;
1777 if (positionX > (((GtkAdjustment *)screen.win.hAdjustment)->upper - ((GtkAdjustment *)screen.win.hAdjustment)->page_size))
1778 positionX = (((GtkAdjustment *)screen.win.hAdjustment)->upper - ((GtkAdjustment *)screen.win.hAdjustment)->page_size);
1779 gtk_adjustment_set_value ((GtkAdjustment *)screen.win.hAdjustment, positionX);
1781 positionY = ((GtkAdjustment *)screen.win.vAdjustment)->upper - screenRenderInfo.lowerLeftY -
1782 ((GtkAdjustment *)screen.win.vAdjustment)->page_size +
1783 ((GtkAdjustment *)screen.win.vAdjustment)->lower;
1784 if (positionY < ((GtkAdjustment *)screen.win.vAdjustment)->lower)
1785 positionY = ((GtkAdjustment *)screen.win.vAdjustment)->lower;
1786 if (positionY > (((GtkAdjustment *)screen.win.vAdjustment)->upper - ((GtkAdjustment *)screen.win.vAdjustment)->page_size))
1787 positionY = (((GtkAdjustment *)screen.win.vAdjustment)->upper - ((GtkAdjustment *)screen.win.vAdjustment)->page_size);
1788 gtk_adjustment_set_value ((GtkAdjustment *)screen.win.vAdjustment, positionY);
1791 /* --------------------------------------------------------- */
1792 gboolean
1793 callbacks_scrollbar_button_released (GtkWidget *widget, GdkEventButton *event){
1794 screen.off_x = 0;
1795 screen.off_y = 0;
1796 screen.state = NORMAL;
1797 render_refresh_rendered_image_on_screen();
1798 return FALSE;
1801 /* --------------------------------------------------------- */
1802 gboolean
1803 callbacks_scrollbar_button_pressed (GtkWidget *widget, GdkEventButton *event){
1804 //screen.last_x = ((GtkAdjustment *)screen.win.hAdjustment)->value;
1805 screen.state = SCROLLBAR;
1806 return FALSE;
1809 /* --------------------------------------------------------- */
1810 void callbacks_hadjustment_value_changed (GtkAdjustment *adjustment, gpointer user_data){
1811 /* make sure we're actually using the scrollbar to make sure we don't reset
1812 lowerLeftX during a scrollbar redraw during something else */
1813 if (screen.state == SCROLLBAR) {
1814 screenRenderInfo.lowerLeftX = gtk_adjustment_get_value (adjustment);
1818 /* --------------------------------------------------------- */
1819 void callbacks_vadjustment_value_changed (GtkAdjustment *adjustment, gpointer user_data){
1820 /* make sure we're actually using the scrollbar to make sure we don't reset
1821 lowerLeftY during a scrollbar redraw during something else */
1822 if (screen.state == SCROLLBAR) {
1823 screenRenderInfo.lowerLeftY = adjustment->upper -
1824 (gtk_adjustment_get_value (adjustment) + adjustment->page_size) + adjustment->lower;
1828 /* --------------------------------------------------------- */
1829 void
1830 callbacks_layer_tree_visibility_button_toggled (GtkCellRendererToggle *cell_renderer,
1831 gchar *path,
1832 gpointer user_data){
1833 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
1834 ((GtkTreeView *) screen.win.layerTree);
1835 GtkTreeIter iter;
1836 gboolean newVisibility=TRUE;
1837 gint index;
1839 gtk_tree_model_get_iter_from_string ((GtkTreeModel *)list_store, &iter, path);
1841 GtkTreePath *treePath = gtk_tree_path_new_from_string (path);
1842 if (gtk_tree_model_get_iter((GtkTreeModel *)list_store, &iter, treePath)) {
1843 gint *indices;
1845 indices = gtk_tree_path_get_indices (treePath);
1846 index = indices[0];
1847 if (mainProject->file[index]->isVisible)
1848 newVisibility = FALSE;
1849 mainProject->file[index]->isVisible = newVisibility;
1850 /* clear any selected items so they don't show after the layer is hidden */
1851 render_clear_selection_buffer();
1853 callbacks_update_layer_tree ();
1854 if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
1855 render_refresh_rendered_image_on_screen();
1857 else {
1858 render_recreate_composite_surface (screen.drawing_area);
1859 callbacks_force_expose_event_for_screen ();
1864 /* --------------------------------------------------------- */
1865 gint
1866 callbacks_get_col_number_from_tree_view_column (GtkTreeViewColumn *col)
1868 GList *cols;
1869 gint num;
1871 g_return_val_if_fail ( col != NULL, -1 );
1872 g_return_val_if_fail ( col->tree_view != NULL, -1 );
1873 cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(col->tree_view));
1874 num = g_list_index(cols, (gpointer) col);
1875 g_list_free(cols);
1876 return num;
1879 /* --------------------------------------------------------- */
1880 void
1881 callbacks_add_layer_button_clicked (GtkButton *button, gpointer user_data) {
1882 callbacks_open_layer_activate (NULL, NULL);
1885 /* --------------------------------------------------------- */
1886 void
1887 callbacks_unselect_all_tool_buttons (void) {
1891 void
1892 callbacks_switch_to_normal_tool_cursor (gint toolNumber) {
1893 GdkCursor *cursor;
1895 switch (toolNumber) {
1896 case POINTER:
1897 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1898 GERBV_DEF_CURSOR);
1899 break;
1900 case PAN:
1901 cursor = gdk_cursor_new(GDK_FLEUR);
1902 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1903 cursor);
1904 gdk_cursor_destroy(cursor);
1905 break;
1906 case ZOOM:
1907 cursor = gdk_cursor_new(GDK_SIZING);
1908 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1909 cursor);
1910 gdk_cursor_destroy(cursor);
1911 break;
1912 case MEASURE:
1913 cursor = gdk_cursor_new(GDK_CROSSHAIR);
1914 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1915 cursor);
1916 gdk_cursor_destroy(cursor);
1917 break;
1918 default:
1919 break;
1923 /* --------------------------------------------------------- */
1924 void
1925 callbacks_switch_to_correct_cursor (void) {
1926 GdkCursor *cursor;
1928 if (screen.state == IN_MOVE) {
1929 cursor = gdk_cursor_new(GDK_FLEUR);
1930 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1931 cursor);
1932 gdk_cursor_destroy(cursor);
1933 return;
1935 else if (screen.state == IN_ZOOM_OUTLINE) {
1936 cursor = gdk_cursor_new(GDK_SIZING);
1937 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1938 cursor);
1939 gdk_cursor_destroy(cursor);
1940 return;
1942 callbacks_switch_to_normal_tool_cursor (screen.tool);
1945 /* --------------------------------------------------------- */
1946 void
1947 callbacks_change_tool (GtkButton *button, gpointer user_data) {
1948 gint toolNumber = GPOINTER_TO_INT (user_data);
1950 /* make sure se don't get caught in endless recursion here */
1951 if (screen.win.updatingTools)
1952 return;
1953 screen.win.updatingTools = TRUE;
1954 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPointer), FALSE);
1955 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPan), FALSE);
1956 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonZoom), FALSE);
1957 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonMeasure), FALSE);
1958 switch (toolNumber) {
1959 case POINTER:
1960 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPointer), TRUE);
1961 screen.tool = POINTER;
1962 screen.state = NORMAL;
1963 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
1964 "Click to select objects in the current layer. Middle click and drag to pan.");
1965 break;
1966 case PAN:
1967 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPan), TRUE);
1968 screen.tool = PAN;
1969 screen.state = NORMAL;
1970 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
1971 "Click and drag to pan. Right click and drag to zoom.");
1972 break;
1973 case ZOOM:
1974 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonZoom), TRUE);
1975 screen.tool = ZOOM;
1976 screen.state = NORMAL;
1977 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
1978 "Click and drag to zoom in. Shift+click to zoom out.");
1979 break;
1980 case MEASURE:
1981 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonMeasure), TRUE);
1982 screen.tool = MEASURE;
1983 screen.state = NORMAL;
1984 snprintf(screen.statusbar.diststr, MAX_DISTLEN, "Click and drag to measure a distance.");
1985 break;
1986 default:
1987 break;
1989 callbacks_switch_to_normal_tool_cursor (toolNumber);
1990 callbacks_update_statusbar();
1991 screen.win.updatingTools = FALSE;
1992 callbacks_force_expose_event_for_screen();
1995 /* --------------------------------------------------------- */
1996 void
1997 callbacks_select_row (gint rowIndex) {
1998 GtkTreeSelection *selection;
1999 GtkTreeIter iter;
2000 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2001 ((GtkTreeView *) screen.win.layerTree);
2003 selection = gtk_tree_view_get_selection((GtkTreeView *) screen.win.layerTree);
2004 if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store), &iter, NULL, rowIndex)) {
2005 gtk_tree_selection_select_iter (selection, &iter);
2009 /* --------------------------------------------------------- */
2011 * This fcn returns the index of selected layer (selected in
2012 * the layer window on left).
2015 gint
2016 callbacks_get_selected_row_index (void) {
2017 GtkTreeSelection *selection;
2018 GtkTreeIter iter;
2019 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2020 ((GtkTreeView *) screen.win.layerTree);
2021 gint index=-1,i=0;
2023 /* This will only work in single or browse selection mode! */
2024 selection = gtk_tree_view_get_selection((GtkTreeView *) screen.win.layerTree);
2025 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
2026 while (gtk_tree_model_iter_nth_child ((GtkTreeModel *)list_store,
2027 &iter, NULL, i)){
2028 if (gtk_tree_selection_iter_is_selected (selection, &iter)) {
2029 return i;
2031 i++;
2034 return index;
2037 /* --------------------------------------------------------- */
2038 void
2039 callbacks_remove_layer_button_clicked (GtkButton *button, gpointer user_data) {
2040 gint index=callbacks_get_selected_row_index();
2042 if ((index >= 0) && (index <= mainProject->last_loaded)) {
2043 render_remove_selected_objects_belonging_to_layer (index);
2044 gerbv_unload_layer (mainProject, index);
2045 callbacks_update_layer_tree ();
2046 callbacks_select_row (0);
2048 if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2049 render_refresh_rendered_image_on_screen();
2051 else {
2052 render_recreate_composite_surface (screen.drawing_area);
2053 callbacks_force_expose_event_for_screen ();
2058 /* --------------------------------------------------------- */
2059 void
2060 callbacks_move_layer_down_menu_activate (GtkMenuItem *menuitem, gpointer user_data) {
2061 callbacks_move_layer_down_button_clicked(NULL, NULL);
2062 gtk_widget_grab_focus (screen.win.layerTree);
2065 /* --------------------------------------------------------- */
2066 void
2067 callbacks_move_layer_down_button_clicked (GtkButton *button, gpointer user_data) {
2068 gint index=callbacks_get_selected_row_index();
2069 if (index < 0) {
2070 show_no_layers_warning ();
2071 return;
2074 if (index < mainProject->last_loaded) {
2075 gerbv_change_layer_order (mainProject, index, index + 1);
2076 callbacks_update_layer_tree ();
2077 callbacks_select_row (index + 1);
2078 if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2079 render_refresh_rendered_image_on_screen ();
2081 else {
2082 render_recreate_composite_surface (screen.drawing_area);
2083 callbacks_force_expose_event_for_screen ();
2088 /* --------------------------------------------------------- */
2089 void
2090 callbacks_move_layer_up_menu_activate (GtkMenuItem *menuitem, gpointer user_data) {
2091 callbacks_move_layer_up_button_clicked (NULL, NULL);
2092 gtk_widget_grab_focus (screen.win.layerTree);
2095 /* --------------------------------------------------------- */
2096 void
2097 callbacks_move_layer_up_button_clicked (GtkButton *button, gpointer user_data) {
2098 gint index=callbacks_get_selected_row_index();
2099 if (index < 0) {
2100 show_no_layers_warning ();
2101 return;
2103 if (index > 0) {
2104 gerbv_change_layer_order (mainProject, index, index - 1);
2105 callbacks_update_layer_tree ();
2106 callbacks_select_row (index - 1);
2107 if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2108 render_refresh_rendered_image_on_screen();
2110 else {
2111 render_recreate_composite_surface (screen.drawing_area);
2112 callbacks_force_expose_event_for_screen ();
2117 /* --------------------------------------------------------- */
2118 void callbacks_layer_tree_row_inserted (GtkTreeModel *tree_model, GtkTreePath *path,
2119 GtkTreeIter *oIter, gpointer user_data) {
2120 gint *indices=NULL,oldPosition,newPosition;
2122 if ((!screen.win.treeIsUpdating)&&(path != NULL)) {
2123 indices = gtk_tree_path_get_indices (path);
2124 if (indices) {
2125 newPosition = indices[0];
2126 oldPosition = callbacks_get_selected_row_index ();
2127 /* compensate for the fact that the old row has already
2128 been removed */
2129 if (oldPosition < newPosition)
2130 newPosition--;
2131 else
2132 oldPosition--;
2133 gerbv_change_layer_order (mainProject, oldPosition, newPosition);
2135 if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2136 render_refresh_rendered_image_on_screen();
2138 else {
2139 render_recreate_composite_surface (screen.drawing_area);
2140 callbacks_force_expose_event_for_screen ();
2142 /* select the new line */
2143 GtkTreeSelection *selection;
2144 GtkTreeIter iter;
2145 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2146 ((GtkTreeView *) screen.win.layerTree);
2148 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(screen.win.layerTree));
2149 if (gtk_tree_model_get_iter ((GtkTreeModel *)list_store, &iter, path))
2150 gtk_tree_selection_select_iter (selection, &iter);
2155 /* --------------------------------------------------------- */
2156 void
2157 callbacks_show_color_picker_dialog (gint index){
2158 screen.win.colorSelectionDialog = NULL;
2159 GtkColorSelectionDialog *cs= (GtkColorSelectionDialog *) gtk_color_selection_dialog_new ("Select a color");
2160 GtkColorSelection *colorsel = (GtkColorSelection *) cs->colorsel;
2162 screen.win.colorSelectionDialog = (GtkWidget *) cs;
2163 screen.win.colorSelectionIndex = index;
2164 if (index >= 0)
2165 gtk_color_selection_set_current_color (colorsel, &mainProject->file[index]->color);
2166 else
2167 gtk_color_selection_set_current_color (colorsel, &mainProject->background);
2168 if ((screenRenderInfo.renderType >= GERBV_RENDER_TYPE_CAIRO_NORMAL)&&(index >= 0)) {
2169 gtk_color_selection_set_has_opacity_control (colorsel, TRUE);
2170 gtk_color_selection_set_current_alpha (colorsel, mainProject->file[index]->alpha);
2172 gtk_widget_show_all((GtkWidget *)cs);
2173 if (gtk_dialog_run ((GtkDialog*)cs) == GTK_RESPONSE_OK) {
2174 GtkColorSelection *colorsel = (GtkColorSelection *) cs->colorsel;
2175 gint rowIndex = screen.win.colorSelectionIndex;
2177 if (index >= 0) {
2178 gtk_color_selection_get_current_color (colorsel, &mainProject->file[rowIndex]->color);
2179 gdk_colormap_alloc_color(gdk_colormap_get_system(), &mainProject->file[rowIndex]->color, FALSE, TRUE);
2181 else {
2182 gtk_color_selection_get_current_color (colorsel, &mainProject->background);
2183 gdk_colormap_alloc_color(gdk_colormap_get_system(), &mainProject->background, FALSE, TRUE);
2185 if ((screenRenderInfo.renderType >= GERBV_RENDER_TYPE_CAIRO_NORMAL)&&(index >= 0)) {
2186 mainProject->file[rowIndex]->alpha = gtk_color_selection_get_current_alpha (colorsel);
2189 callbacks_update_layer_tree ();
2190 render_refresh_rendered_image_on_screen();
2192 gtk_widget_destroy ((GtkWidget *)cs);
2193 screen.win.colorSelectionDialog = NULL;
2196 /* --------------------------------------------------------- */
2197 void
2198 callbacks_invert_layer_clicked (GtkButton *button, gpointer user_data) {
2199 gint index=callbacks_get_selected_row_index();
2200 if (index < 0) {
2201 show_no_layers_warning ();
2202 return;
2204 mainProject->file[index]->transform.inverted = !mainProject->file[index]->transform.inverted;
2205 render_refresh_rendered_image_on_screen ();
2206 callbacks_update_layer_tree ();
2209 /* --------------------------------------------------------- */
2210 void
2211 callbacks_change_layer_color_clicked (GtkButton *button, gpointer user_data) {
2212 gint index=callbacks_get_selected_row_index();
2213 if (index < 0) {
2214 show_no_layers_warning ();
2215 return;
2217 callbacks_show_color_picker_dialog (index);
2220 void
2221 callbacks_change_background_color_clicked (GtkButton *button, gpointer user_data) {
2222 callbacks_show_color_picker_dialog (-1);
2225 /* --------------------------------------------------------------------------- */
2226 void
2227 callbacks_reload_layer_clicked (GtkButton *button, gpointer user_data) {
2228 gint index = callbacks_get_selected_row_index();
2229 if (index < 0) {
2230 show_no_layers_warning ();
2231 return;
2233 render_remove_selected_objects_belonging_to_layer (index);
2234 gerbv_revert_file (mainProject, index);
2235 render_refresh_rendered_image_on_screen ();
2236 callbacks_update_layer_tree();
2239 void
2240 callbacks_change_layer_orientation_clicked (GtkButton *button, gpointer userData){
2241 gint index = callbacks_get_selected_row_index();
2243 if (index < 0) {
2244 show_no_layers_warning ();
2245 return;
2248 interface_show_modify_orientation_dialog(&mainProject->file[index]->transform,screen.unit);
2249 render_refresh_rendered_image_on_screen ();
2250 callbacks_update_layer_tree ();
2253 /* --------------------------------------------------------------------------- */
2254 void
2255 callbacks_change_layer_format_clicked (GtkButton *button, gpointer user_data)
2257 gerbv_HID_Attribute *attr = NULL;
2258 int n = 0;
2259 int i;
2260 gerbv_HID_Attr_Val * results = NULL;
2261 gint index = callbacks_get_selected_row_index();
2262 gchar *type;
2263 gint rc;
2264 if (index < 0) {
2265 show_no_layers_warning ();
2266 return;
2268 dprintf ("%s(): index = %d\n", __FUNCTION__, index);
2269 attr = mainProject->file[index]->image->info->attr_list;
2270 n = mainProject->file[index]->image->info->n_attr;
2271 type = mainProject->file[index]->image->info->type;
2272 if (type == NULL)
2273 type = "Unknown";
2275 if (attr == NULL || n == 0)
2277 interface_show_alert_dialog("This file type does not currently have any editable features",
2278 "Format editing is currently only supported for Excellon drill file formats.",
2279 FALSE,
2280 NULL);
2281 return;
2284 dprintf ("%s(): n = %d, attr = %p\n", __FUNCTION__, n, attr);
2285 if (n > 0)
2287 if (mainProject->file[index]->layer_dirty) {
2288 rc = interface_get_alert_dialog_response ("This layer has changed!",
2289 "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.",
2290 TRUE,
2291 NULL);
2292 if (rc == 0) return; /* Return if user hit Cancel */
2295 results = (gerbv_HID_Attr_Val *) malloc (n * sizeof (gerbv_HID_Attr_Val));
2296 if (results == NULL)
2298 fprintf (stderr, "%s() -- malloc failed\n", __FUNCTION__);
2299 exit (1);
2302 /* non-zero means cancel was picked */
2303 if (attribute_interface_dialog (attr, n, results,
2304 "Edit file format",
2305 type))
2307 return;
2312 dprintf ("%s(): Reloading layer\n", __FUNCTION__);
2313 gerbv_revert_file (mainProject, index);
2315 for (i = 0; i < n; i++)
2317 if (results[i].str_value)
2318 free (results[i].str_value);
2321 if (results)
2322 free (results);
2323 render_refresh_rendered_image_on_screen();
2324 callbacks_update_layer_tree();
2327 /* --------------------------------------------------------------------------- */
2328 gboolean
2329 callbacks_layer_tree_key_press (GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
2330 /* if space is pressed while a color picker icon is in focus,
2331 show the color picker dialog. */
2332 if(event->keyval == GDK_space){
2333 GtkTreeView *tree;
2334 GtkTreePath *path;
2335 GtkTreeViewColumn *col;
2336 gint *indices;
2337 gint idx;
2339 tree = (GtkTreeView *) screen.win.layerTree;
2340 gtk_tree_view_get_cursor (tree, &path, &col);
2341 if (path) {
2342 indices = gtk_tree_path_get_indices (path);
2343 if (indices) {
2344 idx = callbacks_get_col_number_from_tree_view_column (col);
2345 if ((idx == 1) && (indices[0] <= mainProject->last_loaded)){
2346 callbacks_show_color_picker_dialog (indices[0]);
2349 gtk_tree_path_free (path);
2352 /* by default propagate the key press */
2353 return FALSE;
2356 /* --------------------------------------------------------------------------- */
2357 gboolean
2358 callbacks_layer_tree_button_press (GtkWidget *widget, GdkEventButton *event,
2359 gpointer user_data) {
2360 GtkTreePath *path;
2361 GtkTreeIter iter;
2362 GtkTreeViewColumn *column;
2363 gint x,y;
2364 gint columnIndex;
2366 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2367 ((GtkTreeView *) screen.win.layerTree);
2368 if (event->button == 1) {
2369 if (gtk_tree_view_get_path_at_pos ((GtkTreeView *) widget, event->x, event->y,
2370 &path, &column, &x, &y)) {
2371 if (gtk_tree_model_get_iter((GtkTreeModel *)list_store, &iter, path)) {
2372 gint *indices;
2373 indices = gtk_tree_path_get_indices (path);
2374 if (indices) {
2375 columnIndex = callbacks_get_col_number_from_tree_view_column (column);
2376 if ((columnIndex == 1) && (indices[0] <= mainProject->last_loaded)){
2377 callbacks_show_color_picker_dialog (indices[0]);
2378 /* don't propagate the signal, since drag and drop can
2379 sometimes activated during color selection */
2380 return TRUE;
2386 /* don't pop up the menu if we don't have any loaded files */
2387 else if ((event->button == 3)&&(mainProject->last_loaded >= 0)) {
2388 gtk_menu_popup(GTK_MENU(screen.win.layerTreePopupMenu), NULL, NULL, NULL, NULL,
2389 event->button, event->time);
2391 /* always allow the click to propagate and make sure the line is activated */
2392 return FALSE;
2395 /* --------------------------------------------------------------------------- */
2396 void
2397 callbacks_update_layer_tree (void) {
2398 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2399 ((GtkTreeView *) screen.win.layerTree);
2400 gint idx;
2401 GtkTreeIter iter;
2402 GtkTreeSelection *selection;
2403 gint oldSelectedRow;
2405 if (!screen.win.treeIsUpdating) {
2406 screen.win.treeIsUpdating = TRUE;
2408 oldSelectedRow = callbacks_get_selected_row_index();
2409 if (oldSelectedRow < 0)
2410 oldSelectedRow = 0;
2411 gtk_list_store_clear (list_store);
2413 for (idx = 0; idx <= mainProject->last_loaded; idx++) {
2414 if (mainProject->file[idx]) {
2415 GdkPixbuf *pixbuf,*blackPixbuf;
2416 guint32 color;
2418 unsigned char red, green, blue, alpha;
2420 red = (unsigned char) (mainProject->file[idx]->color.red * 255 / G_MAXUINT16) ;
2421 green = (unsigned char) (mainProject->file[idx]->color.green * 255 / G_MAXUINT16) ;
2422 blue = (unsigned char) (mainProject->file[idx]->color.blue *255 / G_MAXUINT16) ;
2423 alpha = (unsigned char) (mainProject->file[idx]->alpha * 255 / G_MAXUINT16) ;
2425 color = (red )* (256*256*256) + (green ) * (256*256) + (blue )* (256) + (alpha );
2426 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 20, 15);
2427 gdk_pixbuf_fill (pixbuf, color);
2429 blackPixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 20, 15);
2430 color = (100 )* (256*256*256) + (100 ) * (256*256) + (100 )* (256) + (150 );
2431 gdk_pixbuf_fill (blackPixbuf, color);
2433 /* copy the color area into the black pixbuf */
2434 gdk_pixbuf_copy_area (pixbuf, 1, 1, 18, 13, blackPixbuf, 1, 1);
2435 /* free the color buffer, since we don't need it anymore */
2436 g_object_unref(pixbuf);
2438 gtk_list_store_append (list_store, &iter);
2440 gchar startChar[2],*modifiedCode;
2441 /* terminate the letter string */
2442 startChar[1] = 0;
2444 gint numberOfModifications = 0;
2445 if (mainProject->file[idx]->transform.inverted) {
2446 startChar[0] = 'I';
2447 numberOfModifications++;
2449 if (mainProject->file[idx]->transform.mirrorAroundX ||
2450 mainProject->file[idx]->transform.mirrorAroundY) {
2451 startChar[0] = 'M';
2452 numberOfModifications++;
2454 if ((fabs(mainProject->file[idx]->transform.translateX) > 0.000001) ||
2455 (fabs(mainProject->file[idx]->transform.translateY) > 0.000001)) {
2456 startChar[0] = 'T';
2457 numberOfModifications++;
2459 if ((fabs(mainProject->file[idx]->transform.scaleX - 1) > 0.000001) ||
2460 (fabs(mainProject->file[idx]->transform.scaleY - 1) > 0.000001)) {
2461 startChar[0] = 'S';
2462 numberOfModifications++;
2464 if ((fabs(mainProject->file[idx]->transform.rotation) > 0.000001)) {
2465 startChar[0] = 'R';
2466 numberOfModifications++;
2468 if (numberOfModifications > 1)
2469 startChar[0] = '*';
2470 if (numberOfModifications == 0)
2471 modifiedCode = g_strdup ("");
2472 else
2473 modifiedCode = g_strdup (startChar);
2475 /* display any unsaved layers differently to show the user they are
2476 unsaved */
2477 gchar *layerName;
2478 if (mainProject->file[idx]->layer_dirty == TRUE) {
2479 /* The layer has unsaved changes in it. Show layer name in italics. */
2480 layerName = g_strconcat ("*","<i>",mainProject->file[idx]->name,"</i>",NULL);
2482 else
2483 /* layer is clean. Show layer name using normal font. */
2484 layerName = g_strdup (mainProject->file[idx]->name);
2486 gtk_list_store_set (list_store, &iter,
2487 0, mainProject->file[idx]->isVisible,
2488 1, blackPixbuf,
2489 2, layerName,
2490 3, modifiedCode,
2491 -1);
2492 g_free (layerName);
2493 g_free (modifiedCode);
2494 /* pixbuf has a refcount of 2 now, as the list store has added its own reference */
2495 g_object_unref(blackPixbuf);
2499 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(screen.win.layerTree));
2501 /* if no line is selected yet, select the first row (if it has data) */
2502 /* or, select the line that was previously selected */
2504 if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
2505 if (gtk_tree_model_iter_nth_child ((GtkTreeModel *) list_store,
2506 &iter, NULL, oldSelectedRow)) {
2507 gtk_tree_selection_select_iter (selection, &iter);
2511 if (mainProject->last_loaded >= 0){
2512 dprintf("%s(): enabling layer menu; index=%d\n", __FUNCTION__, mainProject->last_loaded);
2513 gtk_widget_set_sensitive (screen.win.curLayerMenuItem, TRUE);
2514 }else{
2515 dprintf("%s(): disabling layer menu; index=%d\n", __FUNCTION__, mainProject->last_loaded);
2516 gtk_widget_set_sensitive (screen.win.curLayerMenuItem, FALSE);
2519 screen.win.treeIsUpdating = FALSE;
2523 /* --------------------------------------------------------------------------- */
2524 void
2525 callbacks_display_object_properties_clicked (GtkButton *button, gpointer user_data) {
2526 int i;
2527 gchar *layer_name;
2528 gchar *net_label;
2529 gboolean validAperture;
2531 gint index=callbacks_get_selected_row_index ();
2532 if (index < 0 || screen.selectionInfo.type == GERBV_SELECTION_EMPTY) {
2533 interface_show_alert_dialog("No object is currently selected",
2534 "Objects must be selected using the pointer tool before you can view the object properties.",
2535 FALSE,
2536 NULL);
2537 return;
2540 for (i=0; i<screen.selectionInfo.selectedNodeArray->len; i++){
2541 gerbv_selection_item_t sItem = g_array_index (screen.selectionInfo.selectedNodeArray,
2542 gerbv_selection_item_t, i);
2544 gerbv_net_t *net = sItem.net;
2545 gerbv_image_t *image = sItem.image;
2546 int ap_type=0;
2548 /* get the aperture definition for the selected item */
2549 if (net->aperture > 0) {
2550 ap_type = image->aperture[net->aperture]->type;
2551 validAperture = TRUE;
2553 else {
2554 validAperture = FALSE;
2557 /* Also get layer name specified in file by %LN directive
2558 * (if it exists). */
2559 if (net->layer->name == NULL) {
2560 layer_name = g_strdup("<unnamed layer>");
2561 } else {
2562 layer_name = g_strdup(net->layer->name);
2565 if (net->label == NULL) {
2566 net_label = g_strdup("<unlabeled net>");
2567 } else {
2568 net_label = g_strdup((gchar *)net->label);
2570 if (net->interpolation == GERBV_INTERPOLATION_PAREA_START) {
2571 g_message ("Object type: Polygon\n");
2573 else {
2574 switch (net->aperture_state){
2575 case GERBV_APERTURE_STATE_OFF:
2576 break;
2577 case GERBV_APERTURE_STATE_ON:
2578 if (i!=0) g_message ("\n"); /* Spacing for a pretty display */
2579 switch (net->interpolation) {
2580 case GERBV_INTERPOLATION_x10 :
2581 case GERBV_INTERPOLATION_LINEARx01 :
2582 case GERBV_INTERPOLATION_LINEARx001 :
2583 case GERBV_INTERPOLATION_LINEARx1 :
2584 g_message ("Object type: Line\n");
2585 break;
2586 case GERBV_INTERPOLATION_CW_CIRCULAR :
2587 case GERBV_INTERPOLATION_CCW_CIRCULAR :
2588 g_message ("Object type: Arc\n");
2589 break;
2590 default :
2591 g_message ("Object type: Unknown\n");
2592 break;
2594 g_message (" Exposure: On\n");
2595 if (validAperture) {
2596 g_message (" Aperture used: D%d\n", net->aperture);
2597 g_message (" Aperture type: %s\n", ap_names[ap_type]);
2599 g_message (" Start location: (%g, %g)\n", net->start_x, net->start_y);
2600 g_message (" Stop location: (%g, %g)\n", net->stop_x, net->stop_y);
2601 g_message (" Layer name: %s\n", layer_name);
2602 g_message (" Net label: %s\n", net_label);
2603 g_message (" In file: %s\n", mainProject->file[index]->name);
2604 break;
2605 case GERBV_APERTURE_STATE_FLASH:
2606 if (i!=0) g_message ("\n"); /* Spacing for a pretty display */
2607 g_message ("Object type: Flashed aperture\n");
2608 if (validAperture) {
2609 g_message (" Aperture used: D%d\n", net->aperture);
2610 g_message (" Aperture type: %s\n", ap_names[ap_type]);
2612 g_message (" Location: (%g, %g)\n", net->stop_x, net->stop_y);
2613 g_message (" Layer name: %s\n", layer_name);
2614 g_message (" Net label: %s\n", net_label);
2615 g_message (" In file: %s\n", mainProject->file[index]->name);
2616 break;
2619 g_free (net_label);
2620 g_free (layer_name);
2622 /* Use separator for different report requests */
2623 g_message ("---------------------------------------\n");
2626 void
2627 callbacks_support_benchmark (gerbv_render_info_t *renderInfo) {
2628 int i;
2629 time_t start, now;
2630 GdkPixmap *renderedPixmap = gdk_pixmap_new (NULL, renderInfo->displayWidth,
2631 renderInfo->displayHeight, 24);
2633 // start by running the GDK (fast) rendering test
2634 i = 0;
2635 start = time(NULL);
2636 now = start;
2637 while( now - 30 < start) {
2638 i++;
2639 dprintf("Benchmark(): Starting redraw #%d\n", i);
2640 gerbv_render_to_pixmap_using_gdk (mainProject, renderedPixmap, renderInfo, NULL, NULL);
2641 now = time(NULL);
2642 dprintf("Elapsed time = %ld seconds\n", (long int) (now - start));
2644 g_message("FAST (=GDK) mode benchmark: %d redraws in %ld seconds (%g redraws/second)\n",
2645 i, (long int) (now - start), (double) i / (double)(now - start));
2646 gdk_pixmap_unref(renderedPixmap);
2648 // run the cairo (normal) render mode
2649 i = 0;
2650 start = time(NULL);
2651 now = start;
2652 renderInfo->renderType = GERBV_RENDER_TYPE_CAIRO_NORMAL;
2653 while( now - 30 < start) {
2654 i++;
2655 dprintf("Benchmark(): Starting redraw #%d\n", i);
2656 cairo_surface_t *cSurface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
2657 renderInfo->displayWidth, renderInfo->displayHeight);
2658 cairo_t *cairoTarget = cairo_create (cSurface);
2659 gerbv_render_all_layers_to_cairo_target (mainProject, cairoTarget, renderInfo);
2660 cairo_destroy (cairoTarget);
2661 cairo_surface_destroy (cSurface);
2662 now = time(NULL);
2663 dprintf("Elapsed time = %ld seconds\n", (long int) (now - start));
2665 g_message("NORMAL (=Cairo) mode benchmark: %d redraws in %ld seconds (%g redraws/second)\n",
2666 i, (long int) (now - start), (double) i / (double)(now - start));
2669 /* --------------------------------------------------------------------------- */
2670 void
2671 callbacks_benchmark_clicked (GtkButton *button, gpointer user_data)
2673 // prepare render size and options (canvas size width and height are last 2 variables)
2674 gerbv_render_info_t renderInfo = {1.0, 1.0, 0, 0, 0, 640, 480};
2675 // autoscale the image for now...maybe we don't want to do this in order to
2676 // allow benchmarking of different zoom levels?
2677 gerbv_render_zoom_to_fit_display (mainProject, &renderInfo);
2679 g_message("Full zoom benchmarks\n");
2680 callbacks_support_benchmark (&renderInfo);
2683 g_message("x5 zoom benchmarks\n");
2684 renderInfo.lowerLeftX += (screenRenderInfo.displayWidth /
2685 screenRenderInfo.scaleFactorX) / 3.0;
2686 renderInfo.lowerLeftY += (screenRenderInfo.displayHeight /
2687 screenRenderInfo.scaleFactorY) / 3.0;
2688 renderInfo.scaleFactorX *= 5;
2689 renderInfo.scaleFactorY *= 5;
2690 callbacks_support_benchmark (&renderInfo);
2693 /* --------------------------------------------------------------------------- */
2694 void
2695 callbacks_edit_object_properties_clicked (GtkButton *button, gpointer user_data){
2698 /* --------------------------------------------------------------------------- */
2699 void
2700 callbacks_move_objects_clicked (GtkButton *button, gpointer user_data){
2701 /* for testing, just hard code in some translations here */
2702 gerbv_image_move_selected_objects (screen.selectionInfo.selectedNodeArray, -0.050, 0.050);
2703 callbacks_update_layer_tree();
2704 render_clear_selection_buffer ();
2705 render_refresh_rendered_image_on_screen ();
2708 /* --------------------------------------------------------------------------- */
2709 void
2710 callbacks_reduce_object_area_clicked (GtkButton *button, gpointer user_data){
2711 /* for testing, just hard code in some parameters */
2712 gerbv_image_reduce_area_of_selected_objects (screen.selectionInfo.selectedNodeArray, 0.20, 3, 3, 0.01);
2713 render_clear_selection_buffer ();
2714 render_refresh_rendered_image_on_screen ();
2717 /* --------------------------------------------------------------------------- */
2718 void
2719 callbacks_delete_objects_clicked (GtkButton *button, gpointer user_data){
2720 if (screen.selectionInfo.type == GERBV_SELECTION_EMPTY) {
2721 interface_show_alert_dialog("No object is currently selected",
2722 "Objects must be selected using the pointer tool before they can be deleted.",
2723 FALSE,
2724 NULL);
2725 return;
2728 gint index=callbacks_get_selected_row_index();
2729 if (index < 0)
2730 return;
2732 if (mainProject->check_before_delete == TRUE) {
2733 if (!interface_get_alert_dialog_response(
2734 "Do you want to permanently delete the selected objects?",
2735 "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.",
2736 TRUE,
2737 &(mainProject->check_before_delete)))
2738 return;
2741 gerbv_image_delete_selected_nets (mainProject->file[index]->image,
2742 screen.selectionInfo.selectedNodeArray);
2743 render_refresh_rendered_image_on_screen ();
2744 /* Set layer_dirty flag to TRUE */
2745 mainProject->file[index]->layer_dirty = TRUE;
2746 callbacks_update_layer_tree();
2748 render_clear_selection_buffer ();
2749 callbacks_update_selected_object_message(FALSE);
2752 /* --------------------------------------------------------------------------- */
2753 gboolean
2754 callbacks_drawingarea_configure_event (GtkWidget *widget, GdkEventConfigure *event)
2756 GdkDrawable *drawable = widget->window;
2758 gdk_drawable_get_size (drawable, &screenRenderInfo.displayWidth, &screenRenderInfo.displayHeight);
2760 /* set this up if cairo is compiled, since we may need to switch over to
2761 using the surface at any time */
2762 int x_off=0, y_off=0;
2763 GdkVisual *visual;
2765 if (GDK_IS_WINDOW(widget->window)) {
2766 /* query the window's backbuffer if it has one */
2767 GdkWindow *window = GDK_WINDOW(widget->window);
2768 gdk_window_get_internal_paint_info (window, &drawable, &x_off, &y_off);
2770 visual = gdk_drawable_get_visual (drawable);
2771 if (screen.windowSurface)
2772 cairo_surface_destroy ((cairo_surface_t *)
2773 screen.windowSurface);
2774 #ifdef WIN32
2775 cairo_t *cairoTarget = gdk_cairo_create (GDK_WINDOW(widget->window));
2777 screen.windowSurface = cairo_get_target (cairoTarget);
2778 /* increase surface reference by one so it isn't freed when the cairo_t
2779 is destroyed next */
2780 screen.windowSurface = cairo_surface_reference (screen.windowSurface);
2781 cairo_destroy (cairoTarget);
2782 #else
2783 screen.windowSurface = (gpointer) cairo_xlib_surface_create (GDK_DRAWABLE_XDISPLAY (drawable),
2784 GDK_DRAWABLE_XID (drawable),
2785 GDK_VISUAL_XVISUAL (visual),
2786 screenRenderInfo.displayWidth,
2787 screenRenderInfo.displayHeight);
2788 #endif
2789 /* if this is the first time, go ahead and call autoscale even if we don't
2790 have a model loaded */
2791 if ((screenRenderInfo.scaleFactorX < 0.001)||(screenRenderInfo.scaleFactorY < 0.001)) {
2792 gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
2794 render_refresh_rendered_image_on_screen();
2795 return TRUE;
2798 /* --------------------------------------------------------- */
2799 gboolean
2800 callbacks_drawingarea_expose_event (GtkWidget *widget, GdkEventExpose *event)
2802 if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR) {
2803 GdkPixmap *new_pixmap;
2804 GdkGC *gc = gdk_gc_new(widget->window);
2807 * Create a pixmap with default background
2809 new_pixmap = gdk_pixmap_new(widget->window,
2810 widget->allocation.width,
2811 widget->allocation.height,
2812 -1);
2814 gdk_gc_set_foreground(gc, &mainProject->background);
2816 gdk_draw_rectangle(new_pixmap, gc, TRUE,
2817 event->area.x, event->area.y,
2818 event->area.width, event->area.height);
2821 * Copy gerber pixmap onto background if we have one to copy.
2822 * Do translation at the same time.
2824 if (screen.pixmap != NULL) {
2825 gdk_draw_pixmap(new_pixmap,
2826 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
2827 screen.pixmap,
2828 event->area.x - screen.off_x,
2829 event->area.y - screen.off_y,
2830 event->area.x, event->area.y,
2831 event->area.width, event->area.height);
2835 * Draw the whole thing onto screen
2837 gdk_draw_pixmap(widget->window,
2838 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
2839 new_pixmap,
2840 event->area.x, event->area.y,
2841 event->area.x, event->area.y,
2842 event->area.width, event->area.height);
2844 gdk_pixmap_unref(new_pixmap);
2845 gdk_gc_unref(gc);
2848 * Draw Zooming outline if we are in that mode
2850 if (screen.state == IN_ZOOM_OUTLINE) {
2851 render_draw_zoom_outline(screen.centered_outline_zoom);
2853 else if (screen.state == IN_MEASURE) {
2854 render_draw_measure_distance();
2856 if (screen.tool == MEASURE && screen.state != IN_MEASURE) {
2857 render_toggle_measure_line();
2860 return FALSE;
2863 cairo_t *cr;
2864 int width, height;
2865 int x_off=0, y_off=0;
2866 GdkDrawable *drawable = widget->window;
2867 GdkVisual *visual;
2869 if (GDK_IS_WINDOW(widget->window)) {
2870 /* query the window's backbuffer if it has one */
2871 GdkWindow *window = GDK_WINDOW(widget->window);
2872 gdk_window_get_internal_paint_info (window,
2873 &drawable, &x_off, &y_off);
2875 visual = gdk_drawable_get_visual (drawable);
2876 gdk_drawable_get_size (drawable, &width, &height);
2878 #ifdef WIN32
2879 /* FIXME */
2880 cr = gdk_cairo_create (GDK_WINDOW(widget->window));
2881 #else
2882 cairo_surface_t *buffert;
2884 buffert = (gpointer) cairo_xlib_surface_create (GDK_DRAWABLE_XDISPLAY (drawable),
2885 GDK_DRAWABLE_XID (drawable),
2886 GDK_VISUAL_XVISUAL (visual),
2887 event->area.width, event->area.height);
2888 cr = cairo_create (buffert);
2889 #endif
2890 cairo_translate (cr, -event->area.x + screen.off_x, -event->area.y + screen.off_y);
2891 render_project_to_cairo_target (cr);
2892 cairo_destroy (cr);
2893 #ifndef WIN32
2894 cairo_surface_destroy (buffert);
2895 #endif
2897 if (screen.tool == MEASURE)
2898 render_toggle_measure_line();
2899 return FALSE;
2902 /* Transforms screen coordinates to board ones */
2903 static void
2904 callbacks_screen2board(gdouble *X, gdouble *Y, gint x, gint y) {
2906 /* make sure we don't divide by zero (which is possible if the gui
2907 isn't displayed yet */
2908 if ((screenRenderInfo.scaleFactorX > 0.001)||(screenRenderInfo.scaleFactorY > 0.001)) {
2909 *X = screenRenderInfo.lowerLeftX + (x / screenRenderInfo.scaleFactorX);
2910 *Y = screenRenderInfo.lowerLeftY + ((screenRenderInfo.displayHeight - y)
2911 / screenRenderInfo.scaleFactorY);
2913 else {
2914 *X = *Y = 0.0;
2918 /* --------------------------------------------------------- */
2919 static void
2920 callbacks_update_statusbar_coordinates (gint x, gint y) {
2921 gdouble X, Y;
2923 callbacks_screen2board(&X, &Y, x, y);
2924 if (screen.unit == GERBV_MILS) {
2925 snprintf(screen.statusbar.coordstr, MAX_COORDLEN,
2926 "(%8.2f, %8.2f)",
2927 COORD2MILS(X), COORD2MILS(Y));
2928 } else if (screen.unit == GERBV_MMS) {
2929 snprintf(screen.statusbar.coordstr, MAX_COORDLEN,
2930 "(%8.3f, %8.3f)",
2931 COORD2MMS(X), COORD2MMS(Y));
2932 } else {
2933 snprintf(screen.statusbar.coordstr, MAX_COORDLEN,
2934 "(%4.5f, %4.5f)",
2935 COORD2MILS(X) / 1000.0, COORD2MILS(Y) / 1000.0);
2937 callbacks_update_statusbar();
2940 void
2941 callbacks_update_selected_object_message (gboolean userTriedToSelect) {
2942 if (screen.tool != POINTER)
2943 return;
2945 gint selectionLength = screen.selectionInfo.selectedNodeArray->len;
2946 if ((selectionLength == 0)&&(userTriedToSelect)) {
2947 /* update status bar message to make sure the user knows
2948 about needing to select the layer */
2949 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2950 "<b>No object selected. Objects can only be selected in the active layer.</b>");
2952 else if (selectionLength == 0) {
2953 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2954 "Click to select objects in the current layer. Middle click and drag to pan.");
2956 else if (selectionLength == 1) {
2957 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2958 "1 object is currently selected");
2960 else {
2961 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2962 "%d objects are currently selected",selectionLength);
2964 callbacks_update_statusbar();
2967 /* --------------------------------------------------------- */
2968 gboolean
2969 callbacks_drawingarea_motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
2971 int x, y;
2972 GdkModifierType state;
2974 if (event->is_hint)
2975 gdk_window_get_pointer (event->window, &x, &y, &state);
2976 else {
2977 x = event->x;
2978 y = event->y;
2979 state = event->state;
2982 switch (screen.state) {
2983 case IN_MOVE: {
2984 if (screen.last_x != 0 || screen.last_y != 0) {
2985 /* Move pixmap to get a snappier feel of movement */
2986 screen.off_x += x - screen.last_x;
2987 screen.off_y += y - screen.last_y;
2989 screenRenderInfo.lowerLeftX -= ((x - screen.last_x) / screenRenderInfo.scaleFactorX);
2990 screenRenderInfo.lowerLeftY += ((y - screen.last_y) / screenRenderInfo.scaleFactorY);
2991 callbacks_force_expose_event_for_screen ();
2992 callbacks_update_scrollbar_positions ();
2993 screen.last_x = x;
2994 screen.last_y = y;
2995 break;
2997 case IN_ZOOM_OUTLINE: {
2998 if (screen.last_x || screen.last_y)
2999 render_draw_zoom_outline(screen.centered_outline_zoom);
3000 screen.last_x = x;
3001 screen.last_y = y;
3002 render_draw_zoom_outline(screen.centered_outline_zoom);
3003 break;
3005 case IN_MEASURE: {
3006 /* clear the previous drawn line by drawing over it */
3007 render_toggle_measure_line();
3008 callbacks_screen2board(&(screen.measure_last_x), &(screen.measure_last_y),
3009 x, y);
3010 /* screen.last_[xy] are updated to move the ruler pointers */
3011 screen.last_x = x;
3012 screen.last_y = y;
3013 /* draw the new line and write the new distance */
3014 render_draw_measure_distance();
3015 break;
3017 case IN_SELECTION_DRAG: {
3018 if (screen.last_x || screen.last_y)
3019 render_draw_selection_box_outline();
3020 screen.last_x = x;
3021 screen.last_y = y;
3022 render_draw_selection_box_outline();
3023 break;
3025 default:
3026 screen.last_x = x;
3027 screen.last_y = y;
3028 break;
3030 callbacks_update_statusbar_coordinates (x, y);
3031 callbacks_update_ruler_pointers ();
3032 return TRUE;
3033 } /* motion_notify_event */
3035 /* --------------------------------------------------------- */
3036 gboolean
3037 callbacks_drawingarea_button_press_event (GtkWidget *widget, GdkEventButton *event)
3039 GdkCursor *cursor;
3041 switch (event->button) {
3042 case 1 :
3043 if (screen.tool == POINTER) {
3044 /* select */
3045 /* selection will only work with cairo, so do nothing if it's
3046 not compiled */
3047 screen.state = IN_SELECTION_DRAG;
3048 screen.start_x = event->x;
3049 screen.start_y = event->y;
3051 else if (screen.tool == PAN) {
3052 /* Plain panning */
3053 screen.state = IN_MOVE;
3054 screen.last_x = event->x;
3055 screen.last_y = event->y;
3057 else if (screen.tool == ZOOM) {
3058 screen.state = IN_ZOOM_OUTLINE;
3059 /* Zoom outline mode initiated */
3060 screen.start_x = event->x;
3061 screen.start_y = event->y;
3062 screen.centered_outline_zoom = event->state;
3064 else if (screen.tool == MEASURE) {
3065 screen.state = IN_MEASURE;
3066 callbacks_screen2board(&(screen.measure_start_x), &(screen.measure_start_y),
3067 event->x, event->y);
3068 screen.measure_last_x = screen.measure_start_x;
3069 screen.measure_last_y = screen.measure_start_y;
3070 /* force an expose event to clear any previous measure lines */
3071 callbacks_force_expose_event_for_screen ();
3073 break;
3074 case 2 :
3075 screen.state = IN_MOVE;
3076 screen.last_x = event->x;
3077 screen.last_y = event->y;
3078 cursor = gdk_cursor_new(GDK_FLEUR);
3079 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
3080 cursor);
3081 gdk_cursor_destroy(cursor);
3082 break;
3083 case 3 :
3084 if (screen.tool == POINTER) {
3085 /* if no items are selected, try and find the item the user
3086 is pointing at */
3087 if (screen.selectionInfo.type == GERBV_SELECTION_EMPTY) {
3088 gint index=callbacks_get_selected_row_index();
3089 if ((index >= 0) &&
3090 (index <= mainProject->last_loaded) &&
3091 (mainProject->file[index]->isVisible)) {
3092 render_fill_selection_buffer_from_mouse_click(event->x,event->y,index,TRUE);
3093 } else {
3094 render_clear_selection_buffer ();
3095 render_refresh_rendered_image_on_screen ();
3098 /* only show the popup if we actually have something selected now */
3099 if (screen.selectionInfo.type != GERBV_SELECTION_EMPTY)
3100 gtk_menu_popup(GTK_MENU(screen.win.drawWindowPopupMenu), NULL, NULL, NULL, NULL,
3101 event->button, event->time);
3102 } else {
3103 /* Zoom outline mode initiated */
3104 screen.state = IN_ZOOM_OUTLINE;
3105 screen.start_x = event->x;
3106 screen.start_y = event->y;
3107 screen.centered_outline_zoom = event->state & GDK_SHIFT_MASK;
3108 cursor = gdk_cursor_new(GDK_SIZING);
3109 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
3110 cursor);
3111 gdk_cursor_destroy(cursor);
3113 break;
3114 case 4 : /* Scroll wheel */
3115 render_zoom_display (ZOOM_IN_CMOUSE, 0, event->x, event->y);
3116 break;
3117 case 5 : /* Scroll wheel */
3118 render_zoom_display (ZOOM_OUT_CMOUSE, 0, event->x, event->y);
3119 break;
3120 default:
3121 break;
3123 callbacks_switch_to_correct_cursor ();
3124 return TRUE;
3127 /* --------------------------------------------------------- */
3128 gboolean
3129 callbacks_drawingarea_button_release_event (GtkWidget *widget, GdkEventButton *event)
3131 if (event->type == GDK_BUTTON_RELEASE) {
3132 if (screen.state == IN_MOVE) {
3133 screen.off_x = 0;
3134 screen.off_y = 0;
3135 render_refresh_rendered_image_on_screen();
3136 callbacks_switch_to_normal_tool_cursor (screen.tool);
3138 else if (screen.state == IN_ZOOM_OUTLINE) {
3139 if ((event->state & GDK_SHIFT_MASK) != 0) {
3140 render_zoom_display (ZOOM_OUT_CMOUSE, 0, event->x, event->y);
3142 /* if the user just clicks without dragging, then simply
3143 zoom in a preset amount */
3144 else if ((abs(screen.start_x - event->x) < 4) &&
3145 (abs(screen.start_y - event->y) < 4)) {
3146 render_zoom_display (ZOOM_IN_CMOUSE, 0, event->x, event->y);
3148 else
3149 render_calculate_zoom_from_outline (widget, event);
3150 callbacks_switch_to_normal_tool_cursor (screen.tool);
3152 else if (screen.state == IN_SELECTION_DRAG) {
3153 /* selection will only work with cairo, so do nothing if it's
3154 not compiled */
3155 gint index=callbacks_get_selected_row_index();
3156 /* determine if this was just a click or a box drag */
3157 if ((index >= 0) &&
3158 (mainProject->file[index]->isVisible)) {
3159 gboolean eraseOldSelection = TRUE;
3161 if ((event->state & GDK_SHIFT_MASK) ||
3162 (event->state & GDK_CONTROL_MASK)) {
3163 eraseOldSelection = FALSE;
3165 if ((fabs((double)(screen.last_x - screen.start_x)) < 5) &&
3166 (fabs((double)(screen.last_y - screen.start_y)) < 5))
3167 render_fill_selection_buffer_from_mouse_click(event->x,event->y,index,eraseOldSelection);
3168 else
3169 render_fill_selection_buffer_from_mouse_drag(event->x,event->y,
3170 screen.start_x,screen.start_y,index,eraseOldSelection);
3171 /* check if anything was selected */
3172 callbacks_update_selected_object_message (TRUE);
3173 } else {
3174 render_clear_selection_buffer ();
3175 render_refresh_rendered_image_on_screen ();
3178 screen.last_x = screen.last_y = 0;
3179 screen.state = NORMAL;
3181 return TRUE;
3182 } /* button_release_event */
3184 /* --------------------------------------------------------- */
3185 gboolean
3186 callbacks_window_key_press_event (GtkWidget *widget, GdkEventKey *event)
3188 switch(event->keyval) {
3189 case GDK_Escape:
3190 if (screen.tool == POINTER) {
3191 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3192 "No objects are currently selected");
3193 callbacks_update_statusbar();
3194 render_clear_selection_buffer ();
3196 break;
3197 default:
3198 break;
3201 /* Escape may be used to abort outline zoom and just plain repaint */
3202 if (event->keyval == GDK_Escape) {
3203 screen.state = NORMAL;
3204 render_refresh_rendered_image_on_screen();
3207 return TRUE;
3208 } /* key_press_event */
3210 /* --------------------------------------------------------- */
3211 gboolean
3212 callbacks_window_key_release_event (GtkWidget *widget, GdkEventKey *event)
3214 return TRUE;
3215 } /* key_release_event */
3217 /* --------------------------------------------------------- */
3218 /* Scroll wheel */
3219 gboolean
3220 callbacks_window_scroll_event(GtkWidget *widget, GdkEventScroll *event)
3222 switch (event->direction) {
3223 case GDK_SCROLL_UP:
3224 render_zoom_display (ZOOM_IN_CMOUSE, 0, event->x, event->y);
3225 break;
3226 case GDK_SCROLL_DOWN:
3227 render_zoom_display (ZOOM_OUT_CMOUSE, 0, event->x, event->y);
3228 break;
3229 case GDK_SCROLL_LEFT:
3230 /* Ignore */
3231 case GDK_SCROLL_RIGHT:
3232 /* Ignore */
3233 default:
3234 return TRUE;
3236 return TRUE;
3237 } /* scroll_event */
3240 /* ------------------------------------------------------------------ */
3241 /** Displays additional information in the statusbar.
3242 The Statusbar is divided into three sections:\n
3243 statusbar.coordstr for coords\n
3244 statusbar.diststr for displaying measured distances or the designator
3245 (right click on a graphically marked and also actively selected part)\n
3246 statusbar.msg for e.g. showing progress of actions*/
3247 void
3248 callbacks_update_statusbar(void)
3250 if ((screen.statusbar.coordstr != NULL)&&(GTK_IS_LABEL(screen.win.statusMessageLeft))) {
3251 gtk_label_set_text(GTK_LABEL(screen.win.statusMessageLeft), screen.statusbar.coordstr);
3253 if ((screen.statusbar.diststr != NULL)&&(GTK_IS_LABEL(screen.win.statusMessageRight))) {
3254 gtk_label_set_markup(GTK_LABEL(screen.win.statusMessageRight), screen.statusbar.diststr);
3258 /* --------------------------------------------------------- */
3259 void
3260 callbacks_update_statusbar_measured_distance (gdouble dx, gdouble dy){
3261 gdouble delta = sqrt(dx*dx + dy*dy);
3263 if (screen.unit == GERBV_MILS) {
3264 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3265 "Measured distance: %8.2f mils (%8.2f x, %8.2f y)",
3266 COORD2MILS(delta), COORD2MILS(dx), COORD2MILS(dy));
3268 else if (screen.unit == GERBV_MMS) {
3269 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3270 "Measured distance: %8.3f mms (%8.3f x, %8.3f y)",
3271 COORD2MMS(delta), COORD2MMS(dx), COORD2MMS(dy));
3273 else {
3274 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
3275 "Measured distance: %4.5f inches (%4.5f x, %4.5f y)",
3276 COORD2MILS(delta) / 1000.0, COORD2MILS(dx) / 1000.0,
3277 COORD2MILS(dy) / 1000.0);
3279 callbacks_update_statusbar();
3282 /* --------------------------------------------------------- */
3283 void
3284 callbacks_sidepane_render_type_combo_box_changed (GtkComboBox *widget, gpointer user_data) {
3285 int type = gtk_combo_box_get_active (widget);
3287 dprintf ("%s(): type = %d\n", __FUNCTION__, type);
3289 if (type < 0 || type == screenRenderInfo.renderType)
3290 return;
3292 screenRenderInfo.renderType = type;
3293 callbacks_render_type_changed ();
3296 /* --------------------------------------------------------- */
3297 void
3298 callbacks_viewmenu_rendertype_changed (GtkCheckMenuItem *widget, gpointer user_data) {
3299 gint type = GPOINTER_TO_INT(user_data);
3301 if (type == screenRenderInfo.renderType)
3302 return;
3304 dprintf ("%s(): type = %d\n", __FUNCTION__, type);
3306 screenRenderInfo.renderType = type;
3307 callbacks_render_type_changed ();
3310 /* --------------------------------------------------------- */
3311 void
3312 callbacks_viewmenu_units_changed (GtkCheckMenuItem *widget, gpointer user_data) {
3313 gint unit = GPOINTER_TO_INT(user_data);
3315 if (unit < 0 || unit == screen.unit)
3316 return;
3318 dprintf ("%s(): unit = %d, screen.unit = %d\n", __FUNCTION__, unit, screen.unit);
3320 callbacks_units_changed (unit);
3323 /* --------------------------------------------------------- */
3324 void
3325 callbacks_statusbar_unit_combo_box_changed (GtkComboBox *widget, gpointer user_data) {
3326 int unit = gtk_combo_box_get_active (widget);
3328 if (unit < 0 || unit == screen.unit)
3329 return;
3331 callbacks_units_changed (unit);
3334 /* --------------------------------------------------------- */
3335 void
3336 callbacks_clear_messages_button_clicked (GtkButton *button, gpointer user_data) {
3337 GtkTextBuffer *textbuffer;
3338 GtkTextIter start, end;
3340 textbuffer = gtk_text_view_get_buffer((GtkTextView*)screen.win.messageTextView);
3341 gtk_text_buffer_get_start_iter(textbuffer, &start);
3342 gtk_text_buffer_get_end_iter(textbuffer, &end);
3343 gtk_text_buffer_delete (textbuffer, &start, &end);
3346 /* --------------------------------------------------------- */
3347 void
3348 callbacks_handle_log_messages(const gchar *log_domain, GLogLevelFlags log_level,
3349 const gchar *message, gpointer user_data) {
3350 GtkTextBuffer *textbuffer = NULL;
3351 GtkTextIter iter;
3352 GtkTextTag *tag;
3353 GtkTextMark *StartMark = NULL, *StopMark = NULL;
3354 GtkTextIter StartIter, StopIter;
3356 if (!screen.win.messageTextView)
3357 return;
3359 textbuffer = gtk_text_view_get_buffer((GtkTextView*)screen.win.messageTextView);
3361 /* create a mark for the end of the text. */
3362 gtk_text_buffer_get_end_iter(textbuffer, &iter);
3364 /* get the current end position of the text (it will be the
3365 start of the new text. */
3366 StartMark = gtk_text_buffer_create_mark(textbuffer,
3367 "NewTextStart", &iter, TRUE);
3369 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3370 "blue_foreground");
3371 /* the tag does not exist: create it and let them exist in the tag table.*/
3372 if (tag == NULL) {
3373 tag = gtk_text_buffer_create_tag(textbuffer, "black_foreground",
3374 "foreground", "black", NULL);
3375 tag = gtk_text_buffer_create_tag(textbuffer, "blue_foreground",
3376 "foreground", "blue", NULL);
3377 tag = gtk_text_buffer_create_tag(textbuffer, "red_foreground",
3378 "foreground", "red", NULL);
3379 tag = gtk_text_buffer_create_tag(textbuffer, "darkred_foreground",
3380 "foreground", "darkred", NULL);
3381 tag = gtk_text_buffer_create_tag(textbuffer, "darkblue_foreground",
3382 "foreground", "darkblue", NULL);
3383 tag = gtk_text_buffer_create_tag (textbuffer, "darkgreen_foreground",
3384 "foreground", "darkgreen", NULL);
3385 tag = gtk_text_buffer_create_tag (textbuffer,
3386 "saddlebrown_foreground",
3387 "foreground", "saddlebrown", NULL);
3391 * See rgb.txt for the color names definition
3392 * (on my PC it is on /usr/X11R6/lib/X11/rgb.txt)
3394 switch (log_level & G_LOG_LEVEL_MASK) {
3395 case G_LOG_LEVEL_ERROR:
3396 /* a message of this kind aborts the application calling abort() */
3397 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3398 "red_foreground");
3399 gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
3400 gtk_widget_show(screen.win.sidepane_notebook);
3401 break;
3402 case G_LOG_LEVEL_CRITICAL:
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_WARNING:
3409 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3410 "darkred_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_MESSAGE:
3415 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3416 "darkblue_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_INFO:
3421 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3422 "darkgreen_foreground");
3423 break;
3424 case G_LOG_LEVEL_DEBUG:
3425 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3426 "saddlebrown_foreground");
3427 break;
3428 default:
3429 tag = gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table(textbuffer),
3430 "black_foreground");
3431 break;
3435 * Fatal aborts application. We will try to get the message out anyhow.
3437 if (log_level & G_LOG_FLAG_FATAL)
3438 fprintf(stderr, "Fatal error : %s\n", message);
3440 gtk_text_buffer_insert(textbuffer, &iter, message, -1);
3442 gtk_text_buffer_get_end_iter(textbuffer, &iter);
3444 StopMark = gtk_text_buffer_create_mark(textbuffer,
3445 "NewTextStop", &iter, TRUE);
3447 gtk_text_buffer_get_iter_at_mark(textbuffer, &StartIter, StartMark);
3448 gtk_text_buffer_get_iter_at_mark(textbuffer, &StopIter, StopMark);
3450 gtk_text_buffer_apply_tag(textbuffer, tag, &StartIter, &StopIter);
3453 /* --------------------------------------------------------- */
3454 void callbacks_force_expose_event_for_screen (void){
3456 GdkRectangle update_rect;
3458 update_rect.x = 0;
3459 update_rect.y = 0;
3460 update_rect.width = screenRenderInfo.displayWidth;
3461 update_rect.height = screenRenderInfo.displayHeight;
3463 /* Calls expose_event */
3464 gdk_window_invalidate_rect (screen.drawing_area->window, &update_rect, FALSE);
3466 /* update other gui things that could have changed */
3467 callbacks_update_ruler_scales ();
3468 callbacks_update_scrollbar_limits ();
3469 callbacks_update_scrollbar_positions ();