Fix bug 2841371 (segfault on edit->orientation with no layer loaded)
[geda-gerbv.git] / src / callbacks.c
blob60df65f93cca982b0ee76c45b174b8f95e4b22a9
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 gint callbacks_get_selected_row_index (void);
120 /* --------------------------------------------------------- */
121 GtkWidget *
122 callbacks_generate_alert_dialog (gchar *primaryText, gchar *secondaryText){
123 GtkWidget *dialog, *label;
125 dialog = gtk_dialog_new_with_buttons (primaryText,
126 (GtkWindow *)screen.win.topLevelWindow,
127 GTK_DIALOG_DESTROY_WITH_PARENT,
128 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
129 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
130 NULL);
131 label = gtk_label_new (secondaryText);
132 /* Add the label, and show everything we've added to the dialog. */
133 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
134 label);
135 gtk_widget_show_all (dialog);
136 return dialog;
139 /* --------------------------------------------------------- */
141 * The file -> new menu item was selected. Create new
142 * project.
145 void
146 callbacks_new_activate (GtkMenuItem *menuitem,
147 gpointer user_data)
149 if (mainProject->last_loaded >= 0) {
150 if (!interface_get_alert_dialog_response (
151 "Do you want to close any open layers and start a new project?",
152 "Starting a new project will cause all currently open layers to be closed. Any unsaved changes will be lost.",
153 FALSE,
154 NULL))
155 return;
157 /* Unload all layers and then clear layer window */
158 gerbv_unload_all_layers (mainProject);
159 callbacks_update_layer_tree ();
160 render_clear_selection_buffer ();
162 /* Destroy project info */
163 if (mainProject->project) {
164 g_free(mainProject->project);
165 mainProject->project = NULL;
167 render_refresh_rendered_image_on_screen();
171 /* --------------------------------------------------------- */
173 * The file -> open menu item was selected. Open a
174 * project file.
177 void
178 callbacks_open_project_activate (GtkMenuItem *menuitem,
179 gpointer user_data)
181 gchar *filename=NULL;
182 GtkFileFilter * filter;
184 if (mainProject->last_loaded >= 0) {
185 if (!interface_get_alert_dialog_response (
186 "Do you want to close any open layers and load an existing project?",
187 "Loading a project will cause all currently open layers to be closed. Any unsaved changes will be lost.",
188 FALSE,
189 NULL))
190 return;
193 screen.win.gerber =
194 gtk_file_chooser_dialog_new ("Open project file...",
195 NULL,
196 GTK_FILE_CHOOSER_ACTION_OPEN,
197 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
198 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
199 NULL);
200 gtk_file_chooser_set_current_folder ((GtkFileChooser *) screen.win.gerber,
201 mainProject->path);
203 filter = gtk_file_filter_new();
204 gtk_file_filter_set_name(filter, GERBV_PROJECT_FILE_NAME);
205 gtk_file_filter_add_pattern(filter, GERBV_PROJECT_FILE_PAT);
206 gtk_file_chooser_add_filter ((GtkFileChooser *) screen.win.gerber,
207 filter);
209 filter = gtk_file_filter_new();
210 gtk_file_filter_set_name(filter, "All");
211 gtk_file_filter_add_pattern(filter, "*");
212 gtk_file_chooser_add_filter ((GtkFileChooser *) screen.win.gerber,
213 filter);
215 gtk_widget_show (screen.win.gerber);
216 if (gtk_dialog_run ((GtkDialog*)screen.win.gerber) == GTK_RESPONSE_ACCEPT) {
217 filename =
218 gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (screen.win.gerber));
219 /* update the last folder */
220 g_free (mainProject->path);
221 mainProject->path = gtk_file_chooser_get_current_folder ((GtkFileChooser *) screen.win.gerber);
223 gtk_widget_destroy (screen.win.gerber);
225 if (filename) {
226 gerbv_unload_all_layers (mainProject);
227 main_open_project_from_filename (mainProject, filename);
229 gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
230 render_refresh_rendered_image_on_screen();
231 callbacks_update_layer_tree();
233 return;
237 /* --------------------------------------------------------- */
239 * The file -> open layer menu item was selected. Open a
240 * layer (or layers) from a file.
243 void
244 callbacks_open_layer_activate (GtkMenuItem *menuitem,
245 gpointer user_data)
247 GSList *filenames=NULL;
248 GSList *filename=NULL;
250 screen.win.gerber =
251 gtk_file_chooser_dialog_new ("Open Gerber, drill, or pick & place file(s)...",
252 NULL,
253 GTK_FILE_CHOOSER_ACTION_OPEN,
254 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
255 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
256 NULL);
258 gtk_file_chooser_set_select_multiple((GtkFileChooser *) screen.win.gerber, TRUE);
259 gtk_file_chooser_set_current_folder ((GtkFileChooser *) screen.win.gerber,
260 mainProject->path);
261 gtk_widget_show (screen.win.gerber);
262 if (gtk_dialog_run ((GtkDialog*)screen.win.gerber) == GTK_RESPONSE_ACCEPT) {
263 filenames =
264 gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER (screen.win.gerber));
265 /* update the last folder */
266 g_free (mainProject->path);
267 mainProject->path = gtk_file_chooser_get_current_folder ((GtkFileChooser *) screen.win.gerber);
269 gtk_widget_destroy (screen.win.gerber);
271 /* Now try to open all gerbers specified */
272 for (filename=filenames; filename; filename=filename->next) {
273 gerbv_open_layer_from_filename (mainProject, filename->data);
275 g_slist_free(filenames);
277 gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
278 render_refresh_rendered_image_on_screen();
279 callbacks_update_layer_tree();
281 return;
284 /* --------------------------------------------------------- */
285 void
286 callbacks_revert_activate (GtkMenuItem *menuitem,
287 gpointer user_data)
289 gerbv_revert_all_files (mainProject);
290 render_clear_selection_buffer();
291 callbacks_update_selected_object_message(FALSE);
292 render_refresh_rendered_image_on_screen();
293 callbacks_update_layer_tree();
296 /* --------------------------------------------------------- */
297 void
298 callbacks_save_project_activate (GtkMenuItem *menuitem,
299 gpointer user_data)
301 if (mainProject->project)
302 main_save_project_from_filename (mainProject, mainProject->project);
303 else
304 callbacks_generic_save_activate (menuitem, (gpointer) CALLBACKS_SAVE_PROJECT_AS);
305 callbacks_update_layer_tree();
306 return;
309 /* --------------------------------------------------------- */
310 void
311 callbacks_save_layer_activate (GtkMenuItem *menuitem,
312 gpointer user_data)
314 /* first figure out which layer in the layer side menu is selected */
315 gint index=callbacks_get_selected_row_index();
317 /* Now save that layer */
318 if (index >= 0) {
319 if (!gerbv_save_layer_from_index (mainProject, index, mainProject->file[index]->fullPathname)) {
320 interface_show_alert_dialog("Gerbv cannot export this file type",
321 NULL,
322 FALSE,
323 NULL);
324 mainProject->file[index]->layer_dirty = FALSE;
325 callbacks_update_layer_tree();
326 return;
329 callbacks_update_layer_tree();
330 return;
333 /* --------------------------------------------------------- */
334 void
335 callbacks_generic_save_activate (GtkMenuItem *menuitem,
336 gpointer user_data)
338 gchar *filename=NULL;
339 gint processType = GPOINTER_TO_INT (user_data);
340 gchar *windowTitle=NULL;
341 GtkFileFilter * filter;
343 if (processType == CALLBACKS_SAVE_PROJECT_AS)
344 windowTitle = g_strdup ("Save project as...");
345 else if (processType == CALLBACKS_SAVE_FILE_PS)
346 windowTitle = g_strdup ("Export PS file as...");
347 else if (processType == CALLBACKS_SAVE_FILE_PDF)
348 windowTitle = g_strdup ("Export PDF file as...");
349 else if (processType == CALLBACKS_SAVE_FILE_SVG)
350 windowTitle = g_strdup ("Export SVG file as...");
351 else if (processType == CALLBACKS_SAVE_FILE_PNG)
352 windowTitle = g_strdup ("Export PNG file as...");
353 else if (processType == CALLBACKS_SAVE_FILE_RS274X)
354 windowTitle = g_strdup ("Export RS-274X file as...");
355 else if (processType == CALLBACKS_SAVE_FILE_DRILL)
356 windowTitle = g_strdup ("Export Excellon drill file as...");
357 else if (processType == CALLBACKS_SAVE_LAYER_AS)
358 windowTitle = g_strdup ("Save layer as...");
360 screen.win.gerber =
361 gtk_file_chooser_dialog_new (windowTitle, NULL,
362 GTK_FILE_CHOOSER_ACTION_SAVE,
363 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
364 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
365 NULL);
366 g_free (windowTitle);
368 /* if we're saving or exporting a layer, start off in the location of the
369 loaded file */
370 if (processType != CALLBACKS_SAVE_PROJECT_AS) {
371 gint index=callbacks_get_selected_row_index();
372 if (index >= 0) {
373 gchar *dirName = g_path_get_dirname (mainProject->file[index]->fullPathname);
374 gtk_file_chooser_set_current_folder ((GtkFileChooser *) screen.win.gerber,
375 dirName);
376 g_free (dirName);
380 if (processType == CALLBACKS_SAVE_PROJECT_AS) {
381 filter = gtk_file_filter_new();
382 gtk_file_filter_set_name(filter, GERBV_PROJECT_FILE_NAME);
383 gtk_file_filter_add_pattern(filter, GERBV_PROJECT_FILE_PAT);
384 gtk_file_chooser_add_filter ((GtkFileChooser *) screen.win.gerber,
385 filter);
387 filter = gtk_file_filter_new();
388 gtk_file_filter_set_name(filter, "All");
389 gtk_file_filter_add_pattern(filter, "*");
390 gtk_file_chooser_add_filter ((GtkFileChooser *) screen.win.gerber,
391 filter);
393 gtk_file_chooser_set_current_name ((GtkFileChooser *) screen.win.gerber,
394 "untitled" GERBV_PROJECT_FILE_EXT );
397 gtk_widget_show (screen.win.gerber);
398 if (gtk_dialog_run ((GtkDialog*)screen.win.gerber) == GTK_RESPONSE_ACCEPT) {
399 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (screen.win.gerber));
401 gtk_widget_destroy (screen.win.gerber);
403 if (filename) {
404 if (processType == CALLBACKS_SAVE_PROJECT_AS) {
405 main_save_as_project_from_filename (mainProject, filename);
406 rename_main_window(filename, NULL);
408 else if (processType == CALLBACKS_SAVE_FILE_PS)
409 gerbv_export_postscript_file_from_project_autoscaled (mainProject, filename);
410 else if (processType == CALLBACKS_SAVE_FILE_PDF)
411 gerbv_export_pdf_file_from_project_autoscaled (mainProject, filename);
412 else if (processType == CALLBACKS_SAVE_FILE_SVG)
413 gerbv_export_svg_file_from_project_autoscaled (mainProject, filename);
414 else if (processType == CALLBACKS_SAVE_FILE_PNG)
415 gerbv_export_png_file_from_project_autoscaled (mainProject,
416 screenRenderInfo.displayWidth, screenRenderInfo.displayHeight,
417 filename);
418 else if (processType == CALLBACKS_SAVE_LAYER_AS) {
419 gint index=callbacks_get_selected_row_index();
421 gerbv_save_layer_from_index (mainProject, index, filename);
422 /* rename the file path in the index, so future saves will reference the new file path */
423 g_free (mainProject->file[index]->fullPathname);
424 mainProject->file[index]->fullPathname = g_strdup (filename);
425 g_free (mainProject->file[index]->name);
426 mainProject->file[index]->name = g_path_get_basename (filename);
428 else if (processType == CALLBACKS_SAVE_FILE_RS274X) {
429 gint index=callbacks_get_selected_row_index();
431 gerbv_export_rs274x_file_from_image (filename, mainProject->file[index]->image,
432 &mainProject->file[index]->transform);
434 else if (processType == CALLBACKS_SAVE_FILE_DRILL) {
435 gint index=callbacks_get_selected_row_index();
437 gerbv_export_drill_file_from_image (filename, mainProject->file[index]->image,
438 &mainProject->file[index]->transform);
441 g_free (filename);
442 callbacks_update_layer_tree();
443 return;
446 /* --------------------------------------------------------- */
447 #if GTK_CHECK_VERSION(2,10,0)
449 static void
450 callbacks_begin_print (GtkPrintOperation *operation, GtkPrintContext *context,
451 gpointer user_data) {
452 gtk_print_operation_set_n_pages (operation, 1);
456 /* --------------------------------------------------------- */
457 static void
458 callbacks_print_render_page (GtkPrintOperation *operation,
459 GtkPrintContext *context,
460 gint page_nr,
461 gpointer user_data)
463 GtkPrintSettings *pSettings = gtk_print_operation_get_print_settings (operation);
464 gerbv_render_info_t renderInfo = {1.0, 1.0, 0, 0, 3,
465 (gint) gtk_print_context_get_width (context),
466 (gint) gtk_print_context_get_height (context)};
467 cairo_t *cr;
468 int i;
470 /* have to assume x and y resolutions are the same for now, since we
471 don't support differing scales in the gerb_render_info_t struct yet */
472 gdouble xres = gtk_print_context_get_dpi_x (context);
473 gdouble yres = gtk_print_context_get_dpi_y (context);
474 gdouble scalePercentage = gtk_print_settings_get_scale (pSettings);
475 renderInfo.scaleFactorX = scalePercentage / 100 * xres;
476 renderInfo.scaleFactorY = scalePercentage / 100 * yres;
478 gerbv_render_translate_to_fit_display (mainProject, &renderInfo);
479 cr = gtk_print_context_get_cairo_context (context);
480 for(i = 0; i <= mainProject->last_loaded; i++) {
481 if (mainProject->file[i] && mainProject->file[i]->isVisible) {
482 //cairo_push_group (cr);
483 gerbv_render_layer_to_cairo_target (cr, mainProject->file[i], &renderInfo);
484 //cairo_pop_group_to_source (cr);
485 //cairo_paint_with_alpha (cr, screen.file[i]->alpha);
490 /* --------------------------------------------------------- */
491 void
492 callbacks_print_activate (GtkMenuItem *menuitem, gpointer user_data)
494 GtkPrintOperation *print;
495 GtkPrintOperationResult res;
497 print = gtk_print_operation_new ();
499 g_signal_connect (print, "begin_print", G_CALLBACK (callbacks_begin_print), NULL);
500 g_signal_connect (print, "draw_page", G_CALLBACK (callbacks_print_render_page), NULL);
502 //GtkPrintSettings *pSettings = gtk_print_operation_get_print_settings (print);
504 res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
505 (GtkWindow *) screen.win.topLevelWindow , NULL);
507 g_object_unref (print);
509 #endif /* GTK_CHECK_VERSION(2,10,0) */
511 /* --------------------------------------------------------- */
512 void
513 callbacks_zoom_in_activate (GtkMenuItem *menuitem,
514 gpointer user_data)
516 render_zoom_display (ZOOM_IN, 0, 0, 0);
519 /* --------------------------------------------------------- */
520 void
521 callbacks_zoom_out_activate (GtkMenuItem *menuitem,
522 gpointer user_data)
524 render_zoom_display (ZOOM_OUT, 0, 0, 0);
527 /* --------------------------------------------------------- */
528 void
529 callbacks_fit_to_window_activate (GtkMenuItem *menuitem,
530 gpointer user_data)
532 gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
533 render_refresh_rendered_image_on_screen();
537 /* --------------------------------------------------------- */
539 * The analyze -> analyze Gerbers menu item was selected.
540 * Compile statistics on all open Gerber layers and then display
541 * them.
544 void
545 callbacks_analyze_active_gerbers_activate(GtkMenuItem *menuitem,
546 gpointer user_data)
548 gerbv_stats_t *stats_report;
549 GString *G_report_string = g_string_new(NULL);
550 GString *D_report_string = g_string_new(NULL);
551 GString *M_report_string = g_string_new(NULL);
552 GString *misc_report_string = g_string_new(NULL);
553 GString *general_report_string = g_string_new(NULL);
554 GString *error_report_string = g_string_new(NULL);
555 gerbv_error_list_t *my_error_list;
556 gchar *error_level = NULL;
557 GString *aperture_def_report_string = g_string_new(NULL);
558 GString *aperture_use_report_string = g_string_new(NULL);
559 gerbv_aperture_list_t *my_aperture_list;
560 int idx;
562 /* First get a report of stats & errors accumulated from all layers */
563 stats_report = generate_gerber_analysis();
565 /* General info report */
566 g_string_printf(general_report_string,
567 "General information\n");
568 g_string_append_printf(general_report_string,
569 " Active layer count = %d\n",
570 stats_report->layer_count);
571 g_string_append_printf(general_report_string,
572 "\n\n%-45s %-10s\n",
573 "Files processed",
574 "Layer number");
575 for (idx = 0; idx <= mainProject->last_loaded; idx++) {
576 if (mainProject->file[idx] &&
577 mainProject->file[idx]->isVisible &&
578 (mainProject->file[idx]->image->layertype == GERBV_LAYERTYPE_RS274X) ) {
579 g_string_append_printf(general_report_string,
580 " %-45s %-10d\n", mainProject->file[idx]->name, idx+1);
584 /* Error report (goes into general report tab) */
585 if (stats_report->layer_count == 0) {
586 g_string_printf(error_report_string,
587 "\n\nNo Gerber files active (visible)!\n");
588 } else if (stats_report->error_list->error_text == NULL) {
589 g_string_printf(error_report_string,
590 "\n\nNo errors found in active Gerber file(s)!\n");
591 } else {
592 g_string_printf(error_report_string,
593 "\n\nErrors found in active Gerber file(s):\n");
594 for(my_error_list = stats_report->error_list;
595 my_error_list != NULL;
596 my_error_list = my_error_list->next) {
597 switch(my_error_list->type) {
598 case GERBV_MESSAGE_FATAL: /* We should never get this one since the
599 * program should terminate first.... */
600 error_level = g_strdup_printf("FATAL: ");
601 break;
602 case GERBV_MESSAGE_ERROR:
603 error_level = g_strdup_printf("ERROR: ");
604 break;
605 case GERBV_MESSAGE_WARNING:
606 error_level = g_strdup_printf("WARNING: ");
607 break;
608 case GERBV_MESSAGE_NOTE:
609 error_level = g_strdup_printf("NOTE: ");
610 break;
612 g_string_append_printf(error_report_string,
613 " Layer %d: %s %s",
614 my_error_list->layer,
615 error_level,
616 my_error_list->error_text );
617 g_free(error_level);
622 g_string_append_printf(general_report_string,
623 "%s",
624 error_report_string->str);
625 g_string_free(error_report_string, TRUE);
627 /* Now compile stats related to reading G codes */
628 g_string_printf(G_report_string,
629 "G code statistics (all active layers)\n");
630 g_string_append_printf(G_report_string,
631 "<code> = <number of incidences>\n");
632 g_string_append_printf(G_report_string,
633 "G0 = %-6d (%s)\n",
634 stats_report->G0,
635 "Move");
636 g_string_append_printf(G_report_string,
637 "G1 = %-6d (%s)\n",
638 stats_report->G1,
639 "1X linear interpolation");
640 g_string_append_printf(G_report_string,
641 "G2 = %-6d (%s)\n",
642 stats_report->G2,
643 "CW interpolation");
644 g_string_append_printf(G_report_string,
645 "G3 = %-6d (%s)\n",
646 stats_report->G3,
647 "CCW interpolation");
648 g_string_append_printf(G_report_string,
649 "G4 = %-6d (%s)\n",
650 stats_report->G4,
651 "Comment/ignore block");
652 g_string_append_printf(G_report_string,
653 "G10 = %-6d (%s)\n",
654 stats_report->G10,
655 "10X linear interpolation");
656 g_string_append_printf(G_report_string,
657 "G11 = %-6d (%s)\n",
658 stats_report->G11,
659 "0.1X linear interpolation");
660 g_string_append_printf(G_report_string,
661 "G12 = %-6d (%s)\n",
662 stats_report->G12,
663 "0.01X linear interpolation");
664 g_string_append_printf(G_report_string,
665 "G36 = %-6d (%s)\n",
666 stats_report->G36,
667 "Poly fill on");
668 g_string_append_printf(G_report_string,
669 "G37 = %-6d (%s)\n",
670 stats_report->G37,
671 "Poly fill off");
672 g_string_append_printf(G_report_string,
673 "G54 = %-6d (%s)\n",
674 stats_report->G54,
675 "Tool prepare");
676 g_string_append_printf(G_report_string,
677 "G55 = %-6d (%s)\n",
678 stats_report->G55,
679 "Flash prepare");
680 g_string_append_printf(G_report_string,
681 "G70 = %-6d (%s)\n",
682 stats_report->G70,
683 "Units = inches");
684 g_string_append_printf(G_report_string,
685 "G71 = %-6d (%s)\n",
686 stats_report->G71,
687 "Units = mm");
688 g_string_append_printf(G_report_string,
689 "G74 = %-6d (%s)\n",
690 stats_report->G74,
691 "Disable 360 circ. interpolation");
692 g_string_append_printf(G_report_string,
693 "G75 = %-6d (%s)\n",
694 stats_report->G75,
695 "Enable 360 circ. interpolation");
696 g_string_append_printf(G_report_string,
697 "G90 = %-6d (%s)\n",
698 stats_report->G90,
699 "Absolute units");
700 g_string_append_printf(G_report_string,
701 "G91 = %-6d (%s)\n",
702 stats_report->G91,
703 "Incremental units");
704 g_string_append_printf(G_report_string,
705 "Unknown G codes = %d\n",
706 stats_report->G_unknown);
709 g_string_printf(D_report_string, "D code statistics (all active layers)\n");
710 g_string_append_printf(D_report_string,
711 "<code> = <number of incidences>\n");
712 g_string_append_printf(D_report_string,
713 "D1 = %-6d (%s)\n",
714 stats_report->D1,
715 "Exposure on");
716 g_string_append_printf(D_report_string,
717 "D2 = %-6d (%s)\n",
718 stats_report->D2,
719 "Exposure off");
720 g_string_append_printf(D_report_string,
721 "D3 = %-6d (%s)\n",
722 stats_report->D3,
723 "Flash aperture");
724 g_string_append_printf(D_report_string,
725 "Undefined D codes = %d\n",
726 stats_report->D_unknown);
727 g_string_append_printf(D_report_string,
728 "D code Errors = %d\n",
729 stats_report->D_error);
732 g_string_printf(M_report_string, "M code statistics (all active layers)\n");
733 g_string_append_printf(M_report_string,
734 "<code> = <number of incidences>\n");
735 g_string_append_printf(M_report_string,
736 "M0 = %-6d (%s)\n",
737 stats_report->M0,
738 "Program start");
739 g_string_append_printf(M_report_string,
740 "M1 = %-6d (%s)\n",
741 stats_report->M1,
742 "Program stop");
743 g_string_append_printf(M_report_string,
744 "M2 = %-6d (%s)\n",
745 stats_report->M2,
746 "Program end");
747 g_string_append_printf(M_report_string,
748 "Unknown M codes = %d\n",
749 stats_report->M_unknown);
752 g_string_printf(misc_report_string, "Misc code statistics (all active layers)\n");
753 g_string_append_printf(misc_report_string,
754 "<code> = <number of incidences>\n");
755 g_string_append_printf(misc_report_string,
756 "X = %d\n", stats_report->X);
757 g_string_append_printf(misc_report_string,
758 "Y = %d\n", stats_report->Y);
759 g_string_append_printf(misc_report_string,
760 "I = %d\n", stats_report->I);
761 g_string_append_printf(misc_report_string,
762 "J = %d\n", stats_report->J);
763 g_string_append_printf(misc_report_string,
764 "* = %d\n", stats_report->star);
765 g_string_append_printf(misc_report_string,
766 "Unknown codes = %d\n",
767 stats_report->unknown);
769 /* Report apertures defined in input files. */
771 if (stats_report->aperture_list->number == -1) {
772 g_string_printf(aperture_def_report_string,
773 "No aperture definitions found in Gerber file(s)!\n");
774 } else {
775 g_string_printf(aperture_def_report_string,
776 "Apertures defined in Gerber file(s) (by layer)\n");
777 g_string_append_printf(aperture_def_report_string,
778 " %-6s %-8s %12s %8s %8s %8s\n",
779 "Layer",
780 "D code",
781 "Aperture",
782 "Param[0]",
783 "Param[1]",
784 "Param[2]"
786 for(my_aperture_list = stats_report->aperture_list;
787 my_aperture_list != NULL;
788 my_aperture_list = my_aperture_list->next) {
790 g_string_append_printf(aperture_def_report_string,
791 " %-6d D%-4d%13s %8.3f %8.3f %8.3f\n",
792 my_aperture_list->layer,
793 my_aperture_list->number,
794 ap_names[my_aperture_list->type],
795 my_aperture_list->parameter[0],
796 my_aperture_list->parameter[1],
797 my_aperture_list->parameter[2]
802 /* Report apertures usage count in input files. */
803 if (stats_report->D_code_list->number == -1) {
804 g_string_printf(aperture_use_report_string,
805 "No apertures used in Gerber file(s)!\n");
806 } else {
808 /* Now add list of user-defined D codes (apertures) */
810 g_string_printf(aperture_use_report_string,
811 "Apertures used in Gerber file(s) (all active layers)\n");
812 g_string_append_printf(aperture_use_report_string,
813 "<aperture code> = <number of uses>\n");
814 for (my_aperture_list = stats_report->D_code_list;
815 my_aperture_list != NULL;
816 my_aperture_list = my_aperture_list->next) {
818 g_string_append_printf(aperture_use_report_string,
819 " D%d = %-6d\n",
820 my_aperture_list->number,
821 my_aperture_list->count
827 /* Create top level dialog window for report */
828 GtkWidget *analyze_active_gerbers;
829 analyze_active_gerbers = gtk_dialog_new_with_buttons("Gerber codes report",
830 NULL,
831 GTK_DIALOG_DESTROY_WITH_PARENT,
832 GTK_STOCK_OK,
833 GTK_RESPONSE_ACCEPT,
834 NULL);
835 gtk_container_set_border_width (GTK_CONTAINER (analyze_active_gerbers), 5);
837 gtk_dialog_set_default_response (GTK_DIALOG(analyze_active_gerbers),
838 GTK_RESPONSE_ACCEPT);
839 g_signal_connect (G_OBJECT(analyze_active_gerbers),
840 "response",
841 G_CALLBACK (gtk_widget_destroy),
842 GTK_WIDGET(analyze_active_gerbers));
844 /* Use fixed width font for all reports */
845 PangoFontDescription *font =
846 pango_font_description_from_string ("monospace");
848 /* Create GtkLabel to hold general report text */
849 GtkWidget *general_report_label = gtk_label_new (general_report_string->str);
850 g_string_free (general_report_string, TRUE);
851 gtk_misc_set_alignment(GTK_MISC(general_report_label), 0, 0);
852 gtk_misc_set_padding(GTK_MISC(general_report_label), 13, 13);
853 gtk_label_set_selectable(GTK_LABEL(general_report_label), TRUE);
854 gtk_widget_modify_font (GTK_WIDGET(general_report_label),
855 font);
856 /* Put general report text into scrolled window */
857 GtkWidget *general_code_report_window = gtk_scrolled_window_new (NULL, NULL);
858 /* This throws a warning. Must find different approach.... */
859 gtk_widget_set_size_request(GTK_WIDGET(general_code_report_window),
860 200,
861 300);
862 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(general_code_report_window),
863 GTK_WIDGET(general_report_label));
865 /* Create GtkLabel to hold G code text */
866 GtkWidget *G_report_label = gtk_label_new (G_report_string->str);
867 g_string_free (G_report_string, TRUE);
868 gtk_misc_set_alignment(GTK_MISC(G_report_label), 0, 0);
869 gtk_misc_set_padding(GTK_MISC(G_report_label), 13, 13);
870 gtk_label_set_selectable(GTK_LABEL(G_report_label), TRUE);
871 gtk_widget_modify_font (GTK_WIDGET(G_report_label),
872 font);
874 /* Create GtkLabel to hold D code text */
875 GtkWidget *D_report_label = gtk_label_new (D_report_string->str);
876 g_string_free (D_report_string, TRUE);
877 gtk_misc_set_alignment(GTK_MISC(D_report_label), 0, 0);
878 gtk_misc_set_padding(GTK_MISC(D_report_label), 13, 13);
879 gtk_label_set_selectable(GTK_LABEL(D_report_label), TRUE);
880 gtk_widget_modify_font (GTK_WIDGET(D_report_label),
881 font);
883 /* Create GtkLabel to hold M code text */
884 GtkWidget *M_report_label = gtk_label_new (M_report_string->str);
885 g_string_free (M_report_string, TRUE);
886 gtk_misc_set_alignment(GTK_MISC(M_report_label), 0, 0);
887 gtk_misc_set_padding(GTK_MISC(M_report_label), 13, 13);
888 gtk_label_set_selectable(GTK_LABEL(M_report_label), TRUE);
889 gtk_widget_modify_font (GTK_WIDGET(M_report_label),
890 font);
892 /* Create GtkLabel to hold misc code text */
893 GtkWidget *misc_report_label = gtk_label_new (misc_report_string->str);
894 g_string_free (misc_report_string, TRUE);
895 gtk_misc_set_alignment(GTK_MISC(misc_report_label), 0, 0);
896 gtk_misc_set_padding(GTK_MISC(misc_report_label), 13, 13);
897 gtk_label_set_selectable(GTK_LABEL(misc_report_label), TRUE);
898 gtk_widget_modify_font (GTK_WIDGET(misc_report_label),
899 font);
901 /* Create GtkLabel to hold aperture defintion text */
902 GtkWidget *aperture_def_report_label = gtk_label_new (aperture_def_report_string->str);
903 g_string_free (aperture_def_report_string, TRUE);
904 gtk_misc_set_alignment(GTK_MISC(aperture_def_report_label), 0, 0);
905 gtk_misc_set_padding(GTK_MISC(aperture_def_report_label), 13, 13);
906 gtk_label_set_selectable(GTK_LABEL(aperture_def_report_label), TRUE);
907 gtk_widget_modify_font (GTK_WIDGET(aperture_def_report_label),
908 font);
909 /* Put aperture definintion text into scrolled window */
910 GtkWidget *aperture_def_report_window = gtk_scrolled_window_new (NULL, NULL);
911 /* This throws a warning. Must find different approach.... */
912 gtk_widget_set_size_request(GTK_WIDGET(aperture_def_report_window),
913 200,
914 300);
915 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(aperture_def_report_window),
916 GTK_WIDGET(aperture_def_report_label));
918 /* Create GtkLabel to hold aperture use text */
919 GtkWidget *aperture_use_report_label = gtk_label_new (aperture_use_report_string->str);
920 g_string_free (aperture_use_report_string, TRUE);
921 gtk_misc_set_alignment(GTK_MISC(aperture_use_report_label), 0, 0);
922 gtk_misc_set_padding(GTK_MISC(aperture_use_report_label), 13, 13);
923 gtk_label_set_selectable(GTK_LABEL(aperture_use_report_label), TRUE);
924 gtk_widget_modify_font (GTK_WIDGET(aperture_use_report_label),
925 font);
926 /* Put aperture definintion text into scrolled window */
927 GtkWidget *aperture_use_report_window = gtk_scrolled_window_new (NULL, NULL);
928 /* This throws a warning. Must find different approach.... */
929 gtk_widget_set_size_request(GTK_WIDGET(aperture_use_report_window),
930 200,
931 300);
932 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(aperture_use_report_window),
933 GTK_WIDGET(aperture_use_report_label));
935 /* Create tabbed notebook widget and add report label widgets. */
936 GtkWidget *notebook = gtk_notebook_new();
938 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
939 GTK_WIDGET(general_code_report_window),
940 gtk_label_new("General"));
942 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
943 GTK_WIDGET(G_report_label),
944 gtk_label_new("G codes"));
946 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
947 GTK_WIDGET(D_report_label),
948 gtk_label_new("D codes"));
950 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
951 GTK_WIDGET(M_report_label),
952 gtk_label_new("M codes"));
954 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
955 GTK_WIDGET(misc_report_label),
956 gtk_label_new("Misc. codes"));
958 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
959 GTK_WIDGET(aperture_def_report_window),
960 gtk_label_new("Aperture definitions"));
962 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
963 GTK_WIDGET(aperture_use_report_window),
964 gtk_label_new("Aperture usage"));
967 /* Now put notebook into dialog window and show the whole thing */
968 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(analyze_active_gerbers)->vbox),
969 GTK_WIDGET(notebook));
971 gtk_widget_show_all(analyze_active_gerbers);
973 /* free the stats report */
974 gerbv_stats_destroy (stats_report);
975 return;
979 /* --------------------------------------------------------- */
981 * The analyze -> analyze drill file menu item was selected.
982 * Complie statistics on all open drill layers and then display
983 * them.
986 void
987 callbacks_analyze_active_drill_activate(GtkMenuItem *menuitem,
988 gpointer user_data)
990 gerbv_drill_stats_t *stats_report;
991 GString *G_report_string = g_string_new(NULL);
992 GString *M_report_string = g_string_new(NULL);
993 GString *misc_report_string = g_string_new(NULL);
994 gerbv_drill_list_t *my_drill_list;
995 GString *drill_report_string = g_string_new(NULL);
996 GString *general_report_string = g_string_new(NULL);
997 GString *error_report_string = g_string_new(NULL);
998 gerbv_error_list_t *my_error_list;
999 gchar *error_level = NULL;
1000 int idx;
1002 stats_report = (gerbv_drill_stats_t *) generate_drill_analysis();
1004 /* General and error window strings */
1005 g_string_printf(general_report_string, "General information\n");
1006 g_string_append_printf(general_report_string,
1007 " Active layer count = %d\n",
1008 stats_report->layer_count);
1010 g_string_append_printf(general_report_string,
1011 "\n\nFiles processed:\n");
1012 for (idx = mainProject->last_loaded; idx >= 0; idx--) {
1013 if (mainProject->file[idx] &&
1014 mainProject->file[idx]->isVisible &&
1015 (mainProject->file[idx]->image->layertype == GERBV_LAYERTYPE_DRILL) ) {
1016 g_string_append_printf(general_report_string,
1017 " %s\n",
1018 mainProject->file[idx]->name);
1023 if (stats_report->layer_count == 0) {
1024 g_string_printf(error_report_string, "\n\nNo drill files active (visible)!\n");
1025 } else if (stats_report->error_list->error_text == NULL) {
1026 g_string_printf(error_report_string,
1027 "\n\nNo errors found in active drill file(s)!\n");
1028 } else {
1029 g_string_printf(error_report_string,
1030 "\n\nErrors found in active drill file(s):\n");
1031 for(my_error_list = stats_report->error_list;
1032 my_error_list != NULL;
1033 my_error_list = my_error_list->next) {
1034 switch(my_error_list->type) {
1035 case GERBV_MESSAGE_FATAL: /* We should never get this one since the
1036 * program should terminate first.... */
1037 error_level = g_strdup_printf("FATAL: ");
1038 break;
1039 case GERBV_MESSAGE_ERROR:
1040 error_level = g_strdup_printf("ERROR: ");
1041 break;
1042 case GERBV_MESSAGE_WARNING:
1043 error_level = g_strdup_printf("WARNING: ");
1044 break;
1045 case GERBV_MESSAGE_NOTE:
1046 error_level = g_strdup_printf("NOTE: ");
1047 break;
1049 g_string_append_printf(error_report_string,
1050 " Layer %d: %s %s",
1051 my_error_list->layer,
1052 error_level,
1053 my_error_list->error_text);
1057 g_string_append_printf(general_report_string,
1058 "%s", error_report_string->str);
1059 g_string_free(error_report_string, TRUE);
1062 /* G code window strings */
1063 g_string_printf(G_report_string, "G code statistics (all active layers)\n");
1064 g_string_append_printf(G_report_string,
1065 "<code> = <number of incidences>\n");
1066 g_string_append_printf(G_report_string,
1067 "G00 = %-6d (%s)\n",
1068 stats_report->G00,
1069 "Rout mode");
1070 g_string_append_printf(G_report_string,
1071 "G01 = %-6d (%s)\n",
1072 stats_report->G01,
1073 "1X linear interpolation");
1074 g_string_append_printf(G_report_string,
1075 "G02 = %-6d (%s)\n",
1076 stats_report->G02,
1077 "CW interpolation");
1078 g_string_append_printf(G_report_string,
1079 "G03 = %-6d (%s)\n",
1080 stats_report->G03,
1081 "CCW interpolation");
1082 g_string_append_printf(G_report_string,
1083 "G04 = %-6d (%s)\n",
1084 stats_report->G04,
1085 "Variable dwell");
1086 g_string_append_printf(G_report_string,
1087 "G05 = %-6d (%s)\n",
1088 stats_report->G05,
1089 "Drill mode");
1090 g_string_append_printf(G_report_string,
1091 "G90 = %-6d (%s)\n",
1092 stats_report->G90,
1093 "Absolute units");
1094 g_string_append_printf(G_report_string,
1095 "G91 = %-6d (%s)\n",
1096 stats_report->G91,
1097 "Incremental units");
1098 g_string_append_printf(G_report_string,
1099 "G93 = %-6d (%s)\n",
1100 stats_report->G93,
1101 "Zero set");
1102 g_string_append_printf(G_report_string,
1103 "Unknown G codes = %d\n",
1104 stats_report->G_unknown);
1106 /* M code window strings */
1107 g_string_printf(M_report_string, "M code statistics (all active layers)\n");
1108 g_string_append_printf(M_report_string,
1109 "<code> = <number of incidences>\n");
1110 g_string_append_printf(M_report_string,
1111 "M00 = %-6d (%s)\n",
1112 stats_report->M00,
1113 "End of program");
1114 g_string_append_printf(M_report_string,
1115 "M01 = %-6d (%s)\n",
1116 stats_report->M01,
1117 "End of pattern");
1118 g_string_append_printf(M_report_string,
1119 "M18 = %-6d (%s)\n",
1120 stats_report->M18,
1121 "Tool tip check");
1122 g_string_append_printf(M_report_string,
1123 "M25 = %-6d (%s)\n",
1124 stats_report->M25,
1125 "Begin pattern");
1126 g_string_append_printf(M_report_string,
1127 "M30 = %-6d (%s)\n",
1128 stats_report->M30,
1129 "End program rewind");
1130 g_string_append_printf(M_report_string,
1131 "M31 = %-6d (%s)\n",
1132 stats_report->M31,
1133 "Begin pattern");
1134 g_string_append_printf(M_report_string,
1135 "M45 = %-6d (%s)\n",
1136 stats_report->M45,
1137 "Long message");
1138 g_string_append_printf(M_report_string,
1139 "M47 = %-6d (%s)\n",
1140 stats_report->M47,
1141 "Operator message");
1142 g_string_append_printf(M_report_string,
1143 "M48 = %-6d (%s)\n",
1144 stats_report->M48,
1145 "Begin program header");
1146 g_string_append_printf(M_report_string,
1147 "M71 = %-6d (%s)\n",
1148 stats_report->M71,
1149 "Metric units");
1150 g_string_append_printf(M_report_string,
1151 "M72 = %-6d (%s)\n",
1152 stats_report->M72,
1153 "English units");
1154 g_string_append_printf(M_report_string,
1155 "M95 = %-6d (%s)\n",
1156 stats_report->M95,
1157 "End program header");
1158 g_string_append_printf(M_report_string,
1159 "M97 = %-6d (%s)\n",
1160 stats_report->M97,
1161 "Canned text");
1162 g_string_append_printf(M_report_string,
1163 "M98 = %-6d (%s)\n",
1164 stats_report->M98,
1165 "Canned text");
1166 g_string_append_printf(M_report_string,
1167 "Unknown M codes = %d\n",
1168 stats_report->M_unknown);
1171 /* misc report strings */
1172 g_string_printf(misc_report_string, "Misc code statistics (all active layers)\n");
1173 g_string_append_printf(misc_report_string,
1174 "<code> = <number of incidences>\n");
1175 g_string_append_printf(misc_report_string,
1176 "comments = %d\n",
1177 stats_report->comment);
1178 g_string_append_printf(misc_report_string,
1179 "Unknown codes = %d\n",
1180 stats_report->unknown);
1182 g_string_append_printf(misc_report_string,
1183 "R = %-6d (%s)\n",
1184 stats_report->R,
1185 "Repeat hole");
1187 if (stats_report->detect != NULL ) {
1188 g_string_append_printf(misc_report_string,
1189 "\n%s\n",
1190 stats_report->detect);
1192 /* drill report window strings */
1193 g_string_printf(drill_report_string, "Drills used (all active layers)\n");
1194 g_string_append_printf(drill_report_string, "%10s %8s %8s %8s\n",
1195 "Drill no.", "Dia.", "Units", "Count");
1196 for(my_drill_list = stats_report->drill_list;
1197 my_drill_list != NULL;
1198 my_drill_list = my_drill_list->next) {
1199 if (my_drill_list->drill_num == -1) break; /* No drill list */
1200 g_string_append_printf(drill_report_string,
1201 "%10d %8.3f %8s %8d\n",
1202 my_drill_list->drill_num,
1203 my_drill_list->drill_size,
1204 my_drill_list->drill_unit,
1205 my_drill_list->drill_count);
1208 g_string_append_printf(drill_report_string, "Total drill count %d\n",
1209 stats_report->total_count);
1211 /* Use fixed width font for all reports */
1212 PangoFontDescription *font =
1213 pango_font_description_from_string ("monospace");
1215 /* Create top level dialog window for report */
1216 GtkWidget *analyze_active_drill;
1217 analyze_active_drill = gtk_dialog_new_with_buttons("Drill file codes report",
1218 NULL,
1219 GTK_DIALOG_DESTROY_WITH_PARENT,
1220 GTK_STOCK_OK,
1221 GTK_RESPONSE_ACCEPT,
1222 NULL);
1223 gtk_container_set_border_width (GTK_CONTAINER (analyze_active_drill), 5);
1224 gtk_dialog_set_default_response (GTK_DIALOG(analyze_active_drill),
1225 GTK_RESPONSE_ACCEPT);
1226 g_signal_connect (G_OBJECT(analyze_active_drill),
1227 "response",
1228 G_CALLBACK (gtk_widget_destroy),
1229 GTK_WIDGET(analyze_active_drill));
1231 /* Create GtkLabel to hold general report text */
1232 GtkWidget *general_report_label = gtk_label_new (general_report_string->str);
1233 g_string_free(general_report_string, TRUE);
1234 gtk_misc_set_alignment(GTK_MISC(general_report_label), 0, 0);
1235 gtk_misc_set_padding(GTK_MISC(general_report_label), 13, 13);
1236 gtk_label_set_selectable(GTK_LABEL(general_report_label), TRUE);
1237 gtk_widget_modify_font (GTK_WIDGET(general_report_label),
1238 font);
1240 /* Create GtkLabel to hold G code text */
1241 GtkWidget *G_report_label = gtk_label_new (G_report_string->str);
1242 g_string_free(G_report_string, TRUE);
1243 gtk_misc_set_alignment(GTK_MISC(G_report_label), 0, 0);
1244 gtk_misc_set_padding(GTK_MISC(G_report_label), 13, 13);
1245 gtk_label_set_selectable(GTK_LABEL(G_report_label), TRUE);
1246 gtk_widget_modify_font (GTK_WIDGET(G_report_label),
1247 font);
1249 /* Create GtkLabel to hold M code text */
1250 GtkWidget *M_report_label = gtk_label_new (M_report_string->str);
1251 g_string_free(M_report_string, TRUE);
1252 gtk_misc_set_alignment(GTK_MISC(M_report_label), 0, 0);
1253 gtk_misc_set_padding(GTK_MISC(M_report_label), 13, 13);
1254 gtk_label_set_selectable(GTK_LABEL(M_report_label), TRUE);
1255 gtk_widget_modify_font (GTK_WIDGET(M_report_label),
1256 font);
1258 /* Create GtkLabel to hold misc code text */
1259 GtkWidget *misc_report_label = gtk_label_new (misc_report_string->str);
1260 g_string_free(misc_report_string, TRUE);
1261 gtk_misc_set_alignment(GTK_MISC(misc_report_label), 0, 0);
1262 gtk_misc_set_padding(GTK_MISC(misc_report_label), 13, 13);
1263 gtk_label_set_selectable(GTK_LABEL(misc_report_label), TRUE);
1264 gtk_widget_modify_font (GTK_WIDGET(misc_report_label),
1265 font);
1267 /* Create GtkLabel to hold drills used text */
1268 GtkWidget *drill_report_label = gtk_label_new (drill_report_string->str);
1269 g_string_free(drill_report_string, TRUE);
1270 gtk_misc_set_alignment(GTK_MISC(drill_report_label), 0, 0);
1271 gtk_misc_set_padding(GTK_MISC(drill_report_label), 13, 13);
1272 gtk_label_set_selectable(GTK_LABEL(drill_report_label), TRUE);
1273 gtk_widget_modify_font (GTK_WIDGET(drill_report_label),
1274 font);
1276 /* Create tabbed notebook widget and add report label widgets. */
1277 GtkWidget *notebook = gtk_notebook_new();
1279 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1280 GTK_WIDGET(general_report_label),
1281 gtk_label_new("General"));
1283 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1284 GTK_WIDGET(G_report_label),
1285 gtk_label_new("G codes"));
1287 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1288 GTK_WIDGET(M_report_label),
1289 gtk_label_new("M codes"));
1291 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1292 GTK_WIDGET(misc_report_label),
1293 gtk_label_new("Misc. codes"));
1295 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1296 GTK_WIDGET(drill_report_label),
1297 gtk_label_new("Drills used"));
1299 /* Now put notebook into dialog window and show the whole thing */
1300 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(analyze_active_drill)->vbox),
1301 GTK_WIDGET(notebook));
1302 gtk_widget_show_all(analyze_active_drill);
1303 gerbv_drill_stats_destroy (stats_report);
1304 return;
1307 /* --------------------------------------------------------- */
1308 void
1309 callbacks_control_gerber_options_activate (GtkMenuItem *menuitem,
1310 gpointer user_data)
1315 /* --------------------------------------------------------- */
1316 void
1317 callbacks_online_manual_activate (GtkMenuItem *menuitem,
1318 gpointer user_data)
1323 /* --------------------------------------------------------- */
1325 * The file -> quit menu item was selected.
1326 * Check that all changes have been saved, and then quit.
1329 void
1330 callbacks_quit_activate (GtkMenuItem *menuitem,
1331 gpointer user_data)
1333 gboolean layers_dirty = FALSE;
1334 gint idx;
1336 for (idx = 0; idx<=mainProject->last_loaded; idx++) {
1337 if (mainProject->file[idx] == NULL) break;
1338 layers_dirty = layers_dirty || mainProject->file[idx]->layer_dirty;
1341 if (layers_dirty &&
1342 !interface_get_alert_dialog_response(
1343 "Do you want to close all open layers and quit the program?",
1344 "Quitting the program will cause any unsaved changes to be lost.",
1345 FALSE,
1346 NULL)) {
1347 return;
1349 gerbv_unload_all_layers (mainProject);
1350 gtk_main_quit();
1353 /* --------------------------------------------------------- */
1355 * The help -> about menu item was selected.
1356 * Show the about dialog.
1359 void
1360 callbacks_about_activate (GtkMenuItem *menuitem,
1361 gpointer user_data)
1363 GtkWidget *aboutdialog1;
1364 /* TRANSLATORS: Replace this string with your names, one name per line. */
1365 /* gchar *translators = _("translator-credits"); */
1367 gchar *string = g_strdup_printf ( "gerbv -- a Gerber (RS-274/X) viewer.\n\n"
1368 "This is gerbv version %s\n"
1369 "Compiled on %s at %s\n"
1370 "\n"
1371 "gerbv is part of the gEDA Project.\n"
1372 "\n"
1373 "For more information see:\n"
1374 " gerbv homepage: http://gerbv.gpleda.org/\n"
1375 " gEDA homepage: http://gpleda.org/\n"
1376 " gEDA Wiki: http://geda.seul.org/wiki/",
1377 VERSION, __DATE__, __TIME__);
1378 #if GTK_CHECK_VERSION(2,6,0)
1379 gchar *license = g_strdup_printf("gerbv -- a Gerber (RS-274/X) viewer.\n\n"
1380 "Copyright (C) 2000-2007 Stefan Petersen\n\n"
1381 "This program is free software: you can redistribute it and/or modify\n"
1382 "it under the terms of the GNU General Public License as published by\n"
1383 "the Free Software Foundation, either version 2 of the License, or\n"
1384 "(at your option) any later version.\n\n"
1385 "This program is distributed in the hope that it will be useful,\n"
1386 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1387 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1388 "GNU General Public License for more details.\n\n"
1389 "You should have received a copy of the GNU General Public License\n"
1390 "along with this program. If not, see <http://www.gnu.org/licenses/>.");
1391 #include "authors.c"
1393 aboutdialog1 = gtk_about_dialog_new ();
1394 gtk_container_set_border_width (GTK_CONTAINER (aboutdialog1), 5);
1395 gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (aboutdialog1), VERSION);
1396 gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (aboutdialog1), _("Gerbv"));
1398 /* gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG (aboutdialog1), translators); */
1399 gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (aboutdialog1), string);
1400 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG (aboutdialog1), license);
1402 /* The authors.c file is autogenerated at build time */
1403 gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG (aboutdialog1), authors_string_array);
1404 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG (aboutdialog1), "http://gerbv.gpleda.org/");
1406 g_signal_connect (G_OBJECT(aboutdialog1),"response",
1407 G_CALLBACK (gtk_widget_destroy), GTK_WIDGET(aboutdialog1));
1409 g_free (string);
1410 g_free (license);
1411 #else
1412 aboutdialog1 = gtk_message_dialog_new ( GTK_WINDOW (screen.win.topLevelWindow),
1413 GTK_DIALOG_DESTROY_WITH_PARENT,
1414 GTK_MESSAGE_INFO,
1415 GTK_BUTTONS_CLOSE,
1416 string
1419 gtk_window_set_title ( GTK_WINDOW (aboutdialog1), _("About Gerbv"));
1421 /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
1422 g_signal_connect_swapped (aboutdialog1, "response",
1423 G_CALLBACK (gtk_widget_destroy),
1424 aboutdialog1);
1425 g_free (string);
1426 #endif
1428 gtk_widget_show_all(GTK_WIDGET(aboutdialog1));
1432 /* --------------------------------------------------------- */
1434 * The help -> bugs menu item was selected.
1435 * Show the known bugs window
1438 void
1439 callbacks_bugs_activate (GtkMenuItem *menuitem,
1440 gpointer user_data)
1442 int i;
1443 #include "bugs.c"
1445 /* Create the top level dialog widget with an OK button */
1446 GtkWidget *bugs_dialog = gtk_dialog_new_with_buttons("Known bugs in gerbv",
1447 NULL,
1448 GTK_DIALOG_DESTROY_WITH_PARENT,
1449 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1450 NULL);
1451 gtk_container_set_border_width (GTK_CONTAINER (bugs_dialog), 5);
1452 gtk_dialog_set_default_response (GTK_DIALOG(bugs_dialog),
1453 GTK_RESPONSE_ACCEPT);
1454 g_signal_connect (G_OBJECT(bugs_dialog), "response",
1455 G_CALLBACK (gtk_widget_destroy), GTK_WIDGET(bugs_dialog));
1457 /* First create single bugs_string from bugs_string_array */
1458 GString *bugs_string = g_string_new(NULL);
1459 for (i=0; bugs_string_array[i] != NULL; i++) {
1460 g_string_append_printf(bugs_string,
1461 "%s\n",
1462 bugs_string_array[i]);
1465 /* Create GtkLabel to hold text */
1466 GtkWidget *bugs_label = gtk_label_new (bugs_string->str);
1467 g_string_free(bugs_string, TRUE);
1468 gtk_misc_set_alignment(GTK_MISC(bugs_label), 0, 0);
1469 gtk_misc_set_padding(GTK_MISC(bugs_label), 13, 13);
1471 /* Put text into scrolled window */
1472 GtkWidget *bugs_window = gtk_scrolled_window_new (NULL, NULL);
1473 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(bugs_window),
1474 GTK_WIDGET(bugs_label));
1475 gtk_widget_set_size_request(GTK_WIDGET(bugs_window), 600, 300);
1476 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(bugs_dialog)->vbox),
1477 GTK_WIDGET(bugs_window));
1479 gtk_widget_show_all(GTK_WIDGET(bugs_dialog));
1480 gtk_dialog_run(GTK_DIALOG(bugs_dialog));
1484 /* --------------------------------------------------------- */
1485 gdouble callbacks_calculate_actual_distance (gdouble inputDimension) {
1486 gdouble returnValue = 0.0;
1488 if (screen.unit == GERBV_MILS) {
1489 returnValue = COORD2MILS(inputDimension);
1490 } else if (screen.unit == GERBV_MMS) {
1491 returnValue = COORD2MMS(inputDimension);
1492 } else {
1493 returnValue = COORD2MILS(inputDimension)/1000;
1495 return returnValue;
1498 /* --------------------------------------------------------- */
1499 void callbacks_update_ruler_pointers (void) {
1500 double xPosition, yPosition;
1501 xPosition = screenRenderInfo.lowerLeftX + (screen.last_x / screenRenderInfo.scaleFactorX);
1502 yPosition = screenRenderInfo.lowerLeftY + ((screenRenderInfo.displayHeight - screen.last_y) / screenRenderInfo.scaleFactorY);
1504 if (!((screen.unit == GERBV_MILS) && ((screenRenderInfo.scaleFactorX < 80)||(screenRenderInfo.scaleFactorY < 80)))) {
1505 xPosition = callbacks_calculate_actual_distance (xPosition);
1506 yPosition = callbacks_calculate_actual_distance (yPosition);
1508 g_object_set (G_OBJECT (screen.win.hRuler), "position", xPosition, NULL);
1509 g_object_set (G_OBJECT (screen.win.vRuler), "position", yPosition, NULL);
1512 /* --------------------------------------------------------- */
1513 void callbacks_update_ruler_scales (void) {
1514 double xStart, xEnd, yStart, yEnd;
1516 xStart = screenRenderInfo.lowerLeftX;
1517 yStart = screenRenderInfo.lowerLeftY;
1518 xEnd = screenRenderInfo.lowerLeftX + (screenRenderInfo.displayWidth / screenRenderInfo.scaleFactorX);
1519 yEnd = screenRenderInfo.lowerLeftY + (screenRenderInfo.displayHeight / screenRenderInfo.scaleFactorY);
1520 /* mils can get super crowded with large boards, but inches are too
1521 large for most boards. So, we leave mils in for now and just switch
1522 to inches if the scale factor gets too small */
1523 if (!((screen.unit == GERBV_MILS) && ((screenRenderInfo.scaleFactorX < 80)||(screenRenderInfo.scaleFactorY < 80)))) {
1524 xStart = callbacks_calculate_actual_distance (xStart);
1525 xEnd = callbacks_calculate_actual_distance (xEnd);
1526 yStart = callbacks_calculate_actual_distance (yStart);
1527 yEnd = callbacks_calculate_actual_distance (yEnd);
1529 /* make sure the widgets actually exist before setting (in case this gets
1530 called before everything is realized */
1531 if (screen.win.hRuler)
1532 gtk_ruler_set_range (GTK_RULER (screen.win.hRuler), xStart, xEnd, 0, xEnd - xStart);
1533 /* reverse y min and max, since the ruler starts at the top */
1534 if (screen.win.vRuler)
1535 gtk_ruler_set_range (GTK_RULER (screen.win.vRuler), yEnd, yStart, 0, yEnd - yStart);
1538 /* --------------------------------------------------------- */
1539 void callbacks_update_scrollbar_limits (void){
1540 gerbv_render_info_t tempRenderInfo = {0, 0, 0, 0, 3, screenRenderInfo.displayWidth,
1541 screenRenderInfo.displayHeight};
1543 GtkAdjustment *hAdjust = (GtkAdjustment *)screen.win.hAdjustment;
1544 GtkAdjustment *vAdjust = (GtkAdjustment *)screen.win.vAdjustment;
1545 gerbv_render_zoom_to_fit_display (mainProject, &tempRenderInfo);
1546 hAdjust->lower = tempRenderInfo.lowerLeftX;
1547 hAdjust->page_increment = hAdjust->page_size;
1548 hAdjust->step_increment = hAdjust->page_size / 10.0;
1549 vAdjust->lower = tempRenderInfo.lowerLeftY;
1550 vAdjust->page_increment = vAdjust->page_size;
1551 vAdjust->step_increment = vAdjust->page_size / 10.0;
1552 hAdjust->upper = tempRenderInfo.lowerLeftX + (tempRenderInfo.displayWidth / tempRenderInfo.scaleFactorX);
1553 hAdjust->page_size = screenRenderInfo.displayWidth / screenRenderInfo.scaleFactorX;
1554 vAdjust->upper = tempRenderInfo.lowerLeftY + (tempRenderInfo.displayHeight / tempRenderInfo.scaleFactorY);
1555 vAdjust->page_size = screenRenderInfo.displayHeight / screenRenderInfo.scaleFactorY;
1556 callbacks_update_scrollbar_positions ();
1559 /* --------------------------------------------------------- */
1560 void callbacks_update_scrollbar_positions (void){
1561 gdouble positionX,positionY;
1563 positionX = screenRenderInfo.lowerLeftX;
1564 if (positionX < ((GtkAdjustment *)screen.win.hAdjustment)->lower)
1565 positionX = ((GtkAdjustment *)screen.win.hAdjustment)->lower;
1566 if (positionX > (((GtkAdjustment *)screen.win.hAdjustment)->upper - ((GtkAdjustment *)screen.win.hAdjustment)->page_size))
1567 positionX = (((GtkAdjustment *)screen.win.hAdjustment)->upper - ((GtkAdjustment *)screen.win.hAdjustment)->page_size);
1568 gtk_adjustment_set_value ((GtkAdjustment *)screen.win.hAdjustment, positionX);
1570 positionY = ((GtkAdjustment *)screen.win.vAdjustment)->upper - screenRenderInfo.lowerLeftY -
1571 ((GtkAdjustment *)screen.win.vAdjustment)->page_size +
1572 ((GtkAdjustment *)screen.win.vAdjustment)->lower;
1573 if (positionY < ((GtkAdjustment *)screen.win.vAdjustment)->lower)
1574 positionY = ((GtkAdjustment *)screen.win.vAdjustment)->lower;
1575 if (positionY > (((GtkAdjustment *)screen.win.vAdjustment)->upper - ((GtkAdjustment *)screen.win.vAdjustment)->page_size))
1576 positionY = (((GtkAdjustment *)screen.win.vAdjustment)->upper - ((GtkAdjustment *)screen.win.vAdjustment)->page_size);
1577 gtk_adjustment_set_value ((GtkAdjustment *)screen.win.vAdjustment, positionY);
1580 /* --------------------------------------------------------- */
1581 gboolean
1582 callbacks_scrollbar_button_released (GtkWidget *widget, GdkEventButton *event){
1583 screen.off_x = 0;
1584 screen.off_y = 0;
1585 screen.state = NORMAL;
1586 render_refresh_rendered_image_on_screen();
1587 return FALSE;
1590 /* --------------------------------------------------------- */
1591 gboolean
1592 callbacks_scrollbar_button_pressed (GtkWidget *widget, GdkEventButton *event){
1593 //screen.last_x = ((GtkAdjustment *)screen.win.hAdjustment)->value;
1594 screen.state = SCROLLBAR;
1595 return FALSE;
1598 /* --------------------------------------------------------- */
1599 void callbacks_hadjustment_value_changed (GtkAdjustment *adjustment, gpointer user_data){
1600 /* make sure we're actually using the scrollbar to make sure we don't reset
1601 lowerLeftX during a scrollbar redraw during something else */
1602 if (screen.state == SCROLLBAR) {
1603 screenRenderInfo.lowerLeftX = gtk_adjustment_get_value (adjustment);
1607 /* --------------------------------------------------------- */
1608 void callbacks_vadjustment_value_changed (GtkAdjustment *adjustment, gpointer user_data){
1609 /* make sure we're actually using the scrollbar to make sure we don't reset
1610 lowerLeftY during a scrollbar redraw during something else */
1611 if (screen.state == SCROLLBAR) {
1612 screenRenderInfo.lowerLeftY = adjustment->upper -
1613 (gtk_adjustment_get_value (adjustment) + adjustment->page_size) + adjustment->lower;
1617 /* --------------------------------------------------------- */
1618 void
1619 callbacks_layer_tree_visibility_button_toggled (GtkCellRendererToggle *cell_renderer,
1620 gchar *path,
1621 gpointer user_data){
1622 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
1623 ((GtkTreeView *) screen.win.layerTree);
1624 GtkTreeIter iter;
1625 gboolean newVisibility=TRUE;
1626 gint index;
1628 gtk_tree_model_get_iter_from_string ((GtkTreeModel *)list_store, &iter, path);
1630 GtkTreePath *treePath = gtk_tree_path_new_from_string (path);
1631 if (gtk_tree_model_get_iter((GtkTreeModel *)list_store, &iter, treePath)) {
1632 gint *indeces;
1634 indeces = gtk_tree_path_get_indices (treePath);
1635 index = indeces[0];
1636 if (mainProject->file[index]->isVisible)
1637 newVisibility = FALSE;
1638 mainProject->file[index]->isVisible = newVisibility;
1640 callbacks_update_layer_tree ();
1641 if (screenRenderInfo.renderType < 2) {
1642 render_refresh_rendered_image_on_screen();
1644 else {
1645 render_recreate_composite_surface (screen.drawing_area);
1646 callbacks_force_expose_event_for_screen ();
1651 /* --------------------------------------------------------- */
1652 gint
1653 callbacks_get_col_number_from_tree_view_column (GtkTreeViewColumn *col)
1655 GList *cols;
1656 gint num;
1658 g_return_val_if_fail ( col != NULL, -1 );
1659 g_return_val_if_fail ( col->tree_view != NULL, -1 );
1660 cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(col->tree_view));
1661 num = g_list_index(cols, (gpointer) col);
1662 g_list_free(cols);
1663 return num;
1666 /* --------------------------------------------------------- */
1667 void
1668 callbacks_add_layer_button_clicked (GtkButton *button, gpointer user_data) {
1669 callbacks_open_layer_activate (NULL, NULL);
1672 /* --------------------------------------------------------- */
1673 void
1674 callbacks_unselect_all_tool_buttons (void) {
1678 void
1679 callbacks_switch_to_normal_tool_cursor (gint toolNumber) {
1680 GdkCursor *cursor;
1682 switch (toolNumber) {
1683 case POINTER:
1684 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1685 GERBV_DEF_CURSOR);
1686 break;
1687 case PAN:
1688 cursor = gdk_cursor_new(GDK_FLEUR);
1689 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1690 cursor);
1691 gdk_cursor_destroy(cursor);
1692 break;
1693 case ZOOM:
1694 cursor = gdk_cursor_new(GDK_SIZING);
1695 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1696 cursor);
1697 gdk_cursor_destroy(cursor);
1698 break;
1699 case MEASURE:
1700 cursor = gdk_cursor_new(GDK_CROSSHAIR);
1701 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1702 cursor);
1703 gdk_cursor_destroy(cursor);
1704 break;
1705 default:
1706 break;
1710 /* --------------------------------------------------------- */
1711 void
1712 callbacks_switch_to_correct_cursor (void) {
1713 GdkCursor *cursor;
1715 if (screen.state == IN_MOVE) {
1716 cursor = gdk_cursor_new(GDK_FLEUR);
1717 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1718 cursor);
1719 gdk_cursor_destroy(cursor);
1720 return;
1722 else if (screen.state == IN_ZOOM_OUTLINE) {
1723 cursor = gdk_cursor_new(GDK_SIZING);
1724 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
1725 cursor);
1726 gdk_cursor_destroy(cursor);
1727 return;
1729 callbacks_switch_to_normal_tool_cursor (screen.tool);
1732 /* --------------------------------------------------------- */
1733 void
1734 callbacks_change_tool (GtkButton *button, gpointer user_data) {
1735 gint toolNumber = GPOINTER_TO_INT (user_data);
1737 /* make sure se don't get caught in endless recursion here */
1738 if (screen.win.updatingTools)
1739 return;
1740 screen.win.updatingTools = TRUE;
1741 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPointer), FALSE);
1742 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPan), FALSE);
1743 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonZoom), FALSE);
1744 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonMeasure), FALSE);
1745 switch (toolNumber) {
1746 case POINTER:
1747 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPointer), TRUE);
1748 screen.tool = POINTER;
1749 screen.state = NORMAL;
1750 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
1751 "Click to select objects in the current layer. Middle click and drag to pan.");
1752 break;
1753 case PAN:
1754 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonPan), TRUE);
1755 screen.tool = PAN;
1756 screen.state = NORMAL;
1757 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
1758 "Click and drag to pan. Right click and drag to zoom.");
1759 break;
1760 case ZOOM:
1761 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonZoom), TRUE);
1762 screen.tool = ZOOM;
1763 screen.state = NORMAL;
1764 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
1765 "Click and drag to zoom in. Shift+click to zoom out.");
1766 break;
1767 case MEASURE:
1768 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (screen.win.toolButtonMeasure), TRUE);
1769 screen.tool = MEASURE;
1770 screen.state = NORMAL;
1771 snprintf(screen.statusbar.diststr, MAX_DISTLEN, "Click and drag to measure a distance.");
1772 break;
1773 default:
1774 break;
1776 callbacks_switch_to_normal_tool_cursor (toolNumber);
1777 callbacks_update_statusbar();
1778 screen.win.updatingTools = FALSE;
1779 callbacks_force_expose_event_for_screen();
1782 /* --------------------------------------------------------- */
1783 void
1784 callbacks_select_row (gint rowIndex) {
1785 GtkTreeSelection *selection;
1786 GtkTreeIter iter;
1787 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
1788 ((GtkTreeView *) screen.win.layerTree);
1790 selection = gtk_tree_view_get_selection((GtkTreeView *) screen.win.layerTree);
1791 if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store), &iter, NULL, rowIndex)) {
1792 gtk_tree_selection_select_iter (selection, &iter);
1796 /* --------------------------------------------------------- */
1798 * This fcn returns the index of selected layer (selected in
1799 * the layer window on left).
1802 gint
1803 callbacks_get_selected_row_index (void) {
1804 GtkTreeSelection *selection;
1805 GtkTreeIter iter;
1806 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
1807 ((GtkTreeView *) screen.win.layerTree);
1808 gint index=-1,i=0;
1810 /* This will only work in single or browse selection mode! */
1811 selection = gtk_tree_view_get_selection((GtkTreeView *) screen.win.layerTree);
1812 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
1813 while (gtk_tree_model_iter_nth_child ((GtkTreeModel *)list_store,
1814 &iter, NULL, i)){
1815 if (gtk_tree_selection_iter_is_selected (selection, &iter)) {
1816 return i;
1818 i++;
1821 return index;
1824 /* --------------------------------------------------------- */
1825 void
1826 callbacks_remove_layer_button_clicked (GtkButton *button, gpointer user_data) {
1827 gint index=callbacks_get_selected_row_index();
1829 if ((index >= 0) && (index <= mainProject->last_loaded)) {
1830 render_remove_selected_objects_belonging_to_layer (index);
1831 gerbv_unload_layer (mainProject, index);
1832 callbacks_update_layer_tree ();
1833 callbacks_select_row (0);
1835 if (screenRenderInfo.renderType < 2) {
1836 render_refresh_rendered_image_on_screen();
1838 else {
1839 render_recreate_composite_surface (screen.drawing_area);
1840 callbacks_force_expose_event_for_screen ();
1845 /* --------------------------------------------------------- */
1846 void
1847 callbacks_move_layer_down_button_clicked (GtkButton *button, gpointer user_data) {
1848 gint index=callbacks_get_selected_row_index();
1850 if ((index >= 0) && (index < mainProject->last_loaded)) {
1851 gerbv_change_layer_order (mainProject, index, index + 1);
1852 callbacks_update_layer_tree ();
1853 callbacks_select_row (index + 1);
1854 if (screenRenderInfo.renderType < 2) {
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 void
1866 callbacks_move_layer_up_clicked (GtkButton *button, gpointer user_data) {
1867 gint index=callbacks_get_selected_row_index();
1869 if (index > 0) {
1870 gerbv_change_layer_order (mainProject, index, index - 1);
1871 callbacks_update_layer_tree ();
1872 callbacks_select_row (index - 1);
1873 if (screenRenderInfo.renderType < 2) {
1874 render_refresh_rendered_image_on_screen();
1876 else {
1877 render_recreate_composite_surface (screen.drawing_area);
1878 callbacks_force_expose_event_for_screen ();
1883 /* --------------------------------------------------------- */
1884 void callbacks_layer_tree_row_inserted (GtkTreeModel *tree_model, GtkTreePath *path,
1885 GtkTreeIter *oIter, gpointer user_data) {
1886 gint *indeces=NULL,oldPosition,newPosition;
1888 if ((!screen.win.treeIsUpdating)&&(path != NULL)) {
1889 indeces = gtk_tree_path_get_indices (path);
1890 if (indeces) {
1891 newPosition = indeces[0];
1892 oldPosition = callbacks_get_selected_row_index ();
1893 /* compensate for the fact that the old row has already
1894 been removed */
1895 if (oldPosition < newPosition)
1896 newPosition--;
1897 else
1898 oldPosition--;
1899 gerbv_change_layer_order (mainProject, oldPosition, newPosition);
1901 if (screenRenderInfo.renderType < 2) {
1902 render_refresh_rendered_image_on_screen();
1904 else {
1905 render_recreate_composite_surface (screen.drawing_area);
1906 callbacks_force_expose_event_for_screen ();
1908 /* select the new line */
1909 GtkTreeSelection *selection;
1910 GtkTreeIter iter;
1911 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
1912 ((GtkTreeView *) screen.win.layerTree);
1914 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(screen.win.layerTree));
1915 if (gtk_tree_model_get_iter ((GtkTreeModel *)list_store, &iter, path))
1916 gtk_tree_selection_select_iter (selection, &iter);
1921 /* --------------------------------------------------------- */
1922 void
1923 callbacks_show_color_picker_dialog (gint index){
1924 screen.win.colorSelectionDialog = NULL;
1925 GtkColorSelectionDialog *cs= (GtkColorSelectionDialog *) gtk_color_selection_dialog_new ("Select a color");
1926 GtkColorSelection *colorsel = (GtkColorSelection *) cs->colorsel;
1928 screen.win.colorSelectionDialog = (GtkWidget *) cs;
1929 screen.win.colorSelectionIndex = index;
1930 if (index >= 0)
1931 gtk_color_selection_set_current_color (colorsel, &mainProject->file[index]->color);
1932 else
1933 gtk_color_selection_set_current_color (colorsel, &mainProject->background);
1934 if ((screenRenderInfo.renderType >= 2)&&(index >= 0)) {
1935 gtk_color_selection_set_has_opacity_control (colorsel, TRUE);
1936 gtk_color_selection_set_current_alpha (colorsel, mainProject->file[index]->alpha);
1938 gtk_widget_show_all((GtkWidget *)cs);
1939 if (gtk_dialog_run ((GtkDialog*)cs) == GTK_RESPONSE_OK) {
1940 GtkColorSelection *colorsel = (GtkColorSelection *) cs->colorsel;
1941 gint rowIndex = screen.win.colorSelectionIndex;
1943 if (index >= 0) {
1944 gtk_color_selection_get_current_color (colorsel, &mainProject->file[rowIndex]->color);
1945 gdk_colormap_alloc_color(gdk_colormap_get_system(), &mainProject->file[rowIndex]->color, FALSE, TRUE);
1947 else {
1948 gtk_color_selection_get_current_color (colorsel, &mainProject->background);
1949 gdk_colormap_alloc_color(gdk_colormap_get_system(), &mainProject->background, FALSE, TRUE);
1951 if ((screenRenderInfo.renderType >= 2)&&(index >= 0)) {
1952 mainProject->file[rowIndex]->alpha = gtk_color_selection_get_current_alpha (colorsel);
1955 callbacks_update_layer_tree ();
1956 render_refresh_rendered_image_on_screen();
1958 gtk_widget_destroy ((GtkWidget *)cs);
1959 screen.win.colorSelectionDialog = NULL;
1962 /* --------------------------------------------------------- */
1963 void
1964 callbacks_invert_layer_clicked (GtkButton *button, gpointer user_data) {
1965 gint index=callbacks_get_selected_row_index();
1967 mainProject->file[index]->transform.inverted = !mainProject->file[index]->transform.inverted;
1968 render_refresh_rendered_image_on_screen ();
1969 callbacks_update_layer_tree ();
1972 /* --------------------------------------------------------- */
1973 void
1974 callbacks_change_layer_color_clicked (GtkButton *button, gpointer user_data) {
1975 gint index=callbacks_get_selected_row_index();
1977 callbacks_show_color_picker_dialog (index);
1980 void
1981 callbacks_change_background_color_clicked (GtkButton *button, gpointer user_data) {
1982 callbacks_show_color_picker_dialog (-1);
1985 /* --------------------------------------------------------------------------- */
1986 void
1987 callbacks_reload_layer_clicked (GtkButton *button, gpointer user_data) {
1988 gint index = callbacks_get_selected_row_index();
1990 render_remove_selected_objects_belonging_to_layer (index);
1991 gerbv_revert_file (mainProject, index);
1992 render_refresh_rendered_image_on_screen ();
1993 callbacks_update_layer_tree();
1996 void
1997 callbacks_change_layer_orientation_clicked (GtkButton *button, gpointer userData){
1998 gint index = callbacks_get_selected_row_index();
2000 if (index < 0) {
2001 interface_show_alert_dialog("No layers are currently loaded",
2002 "A layer must be loaded before the orientation can be modified.",
2003 FALSE,
2004 NULL);
2005 return;
2008 interface_show_modify_orientation_dialog(&mainProject->file[index]->transform,screen.unit);
2009 render_refresh_rendered_image_on_screen ();
2010 callbacks_update_layer_tree ();
2013 /* --------------------------------------------------------------------------- */
2014 void
2015 callbacks_change_layer_format_clicked (GtkButton *button, gpointer user_data)
2017 gerbv_HID_Attribute *attr = NULL;
2018 int n = 0;
2019 int i;
2020 gerbv_HID_Attr_Val * results = NULL;
2021 gint index = callbacks_get_selected_row_index();
2022 gchar *type;
2023 gint rc;
2025 dprintf ("%s(): index = %d\n", __FUNCTION__, index);
2026 attr = mainProject->file[index]->image->info->attr_list;
2027 n = mainProject->file[index]->image->info->n_attr;
2028 type = mainProject->file[index]->image->info->type;
2029 if (type == NULL)
2030 type = "Unknown";
2032 if (attr == NULL || n == 0)
2034 interface_show_alert_dialog("This file type does not currently have any editable features",
2035 "Format editing is currently only supported for Excellon drill file formats.",
2036 FALSE,
2037 NULL);
2038 return;
2041 dprintf ("%s(): n = %d, attr = %p\n", __FUNCTION__, n, attr);
2042 if (n > 0)
2044 if (mainProject->file[index]->layer_dirty) {
2045 rc = interface_get_alert_dialog_response ("This layer has changed!",
2046 "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.",
2047 TRUE,
2048 NULL);
2049 if (rc == 0) return; /* Return if user hit Cancel */
2052 results = (gerbv_HID_Attr_Val *) malloc (n * sizeof (gerbv_HID_Attr_Val));
2053 if (results == NULL)
2055 fprintf (stderr, "%s() -- malloc failed\n", __FUNCTION__);
2056 exit (1);
2059 /* non-zero means cancel was picked */
2060 if (attribute_interface_dialog (attr, n, results,
2061 "Edit file format",
2062 type))
2064 return;
2069 dprintf ("%s(): Reloading layer\n", __FUNCTION__);
2070 gerbv_revert_file (mainProject, index);
2072 for (i = 0; i < n; i++)
2074 if (results[i].str_value)
2075 free (results[i].str_value);
2078 if (results)
2079 free (results);
2080 render_refresh_rendered_image_on_screen();
2081 callbacks_update_layer_tree();
2084 /* --------------------------------------------------------------------------- */
2085 gboolean
2086 callbacks_layer_tree_button_press (GtkWidget *widget, GdkEventButton *event,
2087 gpointer user_data) {
2088 GtkTreePath *path;
2089 GtkTreeIter iter;
2090 GtkTreeViewColumn *column;
2091 gint x,y;
2092 gint columnIndex;
2094 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2095 ((GtkTreeView *) screen.win.layerTree);
2096 if (event->button == 1) {
2097 if (gtk_tree_view_get_path_at_pos ((GtkTreeView *) widget, event->x, event->y,
2098 &path, &column, &x, &y)) {
2099 if (gtk_tree_model_get_iter((GtkTreeModel *)list_store, &iter, path)) {
2100 gint *indeces;
2101 indeces = gtk_tree_path_get_indices (path);
2102 if (indeces) {
2103 columnIndex = callbacks_get_col_number_from_tree_view_column (column);
2104 if ((columnIndex == 1) && (indeces[0] <= mainProject->last_loaded)){
2105 callbacks_show_color_picker_dialog (indeces[0]);
2106 /* don't propagate the signal, since drag and drop can
2107 sometimes activated during color selection */
2108 return TRUE;
2114 /* don't pop up the menu if we don't have any loaded files */
2115 else if ((event->button == 3)&&(mainProject->last_loaded >= 0)) {
2116 gtk_menu_popup(GTK_MENU(screen.win.layerTreePopupMenu), NULL, NULL, NULL, NULL,
2117 event->button, event->time);
2119 /* always allow the click to propagate and make sure the line is activated */
2120 return FALSE;
2123 /* --------------------------------------------------------------------------- */
2124 void
2125 callbacks_update_layer_tree (void) {
2126 GtkListStore *list_store = (GtkListStore *) gtk_tree_view_get_model
2127 ((GtkTreeView *) screen.win.layerTree);
2128 gint idx;
2129 GtkTreeIter iter;
2130 GtkTreeSelection *selection;
2131 gint oldSelectedRow;
2133 if (!screen.win.treeIsUpdating) {
2134 screen.win.treeIsUpdating = TRUE;
2136 oldSelectedRow = callbacks_get_selected_row_index();
2137 if (oldSelectedRow < 0)
2138 oldSelectedRow = 0;
2139 gtk_list_store_clear (list_store);
2141 for (idx = 0; idx <= mainProject->last_loaded; idx++) {
2142 if (mainProject->file[idx]) {
2143 GdkPixbuf *pixbuf,*blackPixbuf;
2144 guint32 color;
2146 unsigned char red, green, blue, alpha;
2148 red = (unsigned char) (mainProject->file[idx]->color.red * 255 / G_MAXUINT16) ;
2149 green = (unsigned char) (mainProject->file[idx]->color.green * 255 / G_MAXUINT16) ;
2150 blue = (unsigned char) (mainProject->file[idx]->color.blue *255 / G_MAXUINT16) ;
2151 alpha = (unsigned char) (mainProject->file[idx]->alpha * 255 / G_MAXUINT16) ;
2153 color = (red )* (256*256*256) + (green ) * (256*256) + (blue )* (256) + (alpha );
2154 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 20, 15);
2155 gdk_pixbuf_fill (pixbuf, color);
2157 blackPixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 20, 15);
2158 color = (100 )* (256*256*256) + (100 ) * (256*256) + (100 )* (256) + (150 );
2159 gdk_pixbuf_fill (blackPixbuf, color);
2161 /* copy the color area into the black pixbuf */
2162 gdk_pixbuf_copy_area (pixbuf, 1, 1, 18, 13, blackPixbuf, 1, 1);
2163 /* free the color buffer, since we don't need it anymore */
2164 g_object_unref(pixbuf);
2166 gtk_list_store_append (list_store, &iter);
2168 gchar startChar[2],*modifiedCode;
2169 /* terminate the letter string */
2170 startChar[1] = 0;
2172 gint numberOfModifications = 0;
2173 if (mainProject->file[idx]->transform.inverted) {
2174 startChar[0] = 'I';
2175 numberOfModifications++;
2177 if (mainProject->file[idx]->transform.mirrorAroundX ||
2178 mainProject->file[idx]->transform.mirrorAroundY) {
2179 startChar[0] = 'M';
2180 numberOfModifications++;
2182 if ((abs(mainProject->file[idx]->transform.translateX) > 0.000001) ||
2183 (fabs(mainProject->file[idx]->transform.translateY) > 0.000001)) {
2184 startChar[0] = 'T';
2185 numberOfModifications++;
2187 if ((abs(mainProject->file[idx]->transform.scaleX - 1) > 0.000001) ||
2188 (fabs(mainProject->file[idx]->transform.scaleY - 1) > 0.000001)) {
2189 startChar[0] = 'S';
2190 numberOfModifications++;
2192 if ((fabs(mainProject->file[idx]->transform.rotation) > 0.000001)) {
2193 startChar[0] = 'R';
2194 numberOfModifications++;
2196 if (numberOfModifications > 1)
2197 startChar[0] = '*';
2198 if (numberOfModifications == 0)
2199 modifiedCode = g_strdup ("");
2200 else
2201 modifiedCode = g_strdup (startChar);
2203 /* display any unsaved layers differently to show the user they are
2204 unsaved */
2205 gchar *layerName;
2206 if (mainProject->file[idx]->layer_dirty == TRUE) {
2207 /* The layer has unsaved changes in it. Show layer name in italics. */
2208 layerName = g_strconcat ("*","<i>",mainProject->file[idx]->name,"</i>",NULL);
2210 else
2211 /* layer is clean. Show layer name using normal font. */
2212 layerName = g_strdup (mainProject->file[idx]->name);
2214 gtk_list_store_set (list_store, &iter,
2215 0, mainProject->file[idx]->isVisible,
2216 1, blackPixbuf,
2217 2, layerName,
2218 3, modifiedCode,
2219 -1);
2220 g_free (layerName);
2221 g_free (modifiedCode);
2222 /* pixbuf has a refcount of 2 now, as the list store has added its own reference */
2223 g_object_unref(blackPixbuf);
2227 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(screen.win.layerTree));
2229 /* if no line is selected yet, select the first row (if it has data) */
2230 /* or, select the line that was previously selected */
2232 if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
2233 if (gtk_tree_model_iter_nth_child ((GtkTreeModel *) list_store,
2234 &iter, NULL, oldSelectedRow)) {
2235 gtk_tree_selection_select_iter (selection, &iter);
2238 screen.win.treeIsUpdating = FALSE;
2242 /* --------------------------------------------------------------------------- */
2243 void
2244 callbacks_display_object_properties_clicked (GtkButton *button, gpointer user_data){
2245 int i;
2246 gchar *layer_name;
2247 gchar *net_label;
2248 gboolean validAperture;
2250 gint index=callbacks_get_selected_row_index();
2251 if (index < 0)
2252 return;
2254 if (screen.selectionInfo.type == GERBV_SELECTION_EMPTY) {
2255 interface_show_alert_dialog("No object is currently selected",
2256 "Objects must be selected using the pointer tool before you can view the object properties.",
2257 FALSE,
2258 NULL);
2259 return;
2262 for (i=0; i<screen.selectionInfo.selectedNodeArray->len; i++){
2263 gerbv_selection_item_t sItem = g_array_index (screen.selectionInfo.selectedNodeArray,
2264 gerbv_selection_item_t, i);
2266 gerbv_net_t *net = sItem.net;
2267 gerbv_image_t *image = sItem.image;
2268 int ap_type=0;
2270 /* get the aperture definition for the selected item */
2271 if (net->aperture > 0) {
2272 ap_type = image->aperture[net->aperture]->type;
2273 validAperture = TRUE;
2275 else {
2276 validAperture = FALSE;
2279 /* Also get layer name specified in file by %LN directive
2280 * (if it exists). */
2281 if (net->layer->name == NULL) {
2282 layer_name = g_strdup("<unnamed layer>");
2283 } else {
2284 layer_name = g_strdup(net->layer->name);
2287 if (net->label == NULL) {
2288 net_label = g_strdup("<unlabeled net>");
2289 } else {
2290 net_label = g_strdup((gchar *)net->label);
2292 if (net->interpolation == GERBV_INTERPOLATION_PAREA_START) {
2293 g_message ("Object type: Polygon\n");
2295 else {
2296 switch (net->aperture_state){
2297 case GERBV_APERTURE_STATE_OFF:
2298 break;
2299 case GERBV_APERTURE_STATE_ON:
2300 if (i!=0) g_message ("\n"); /* Spacing for a pretty display */
2301 switch (net->interpolation) {
2302 case GERBV_INTERPOLATION_x10 :
2303 case GERBV_INTERPOLATION_LINEARx01 :
2304 case GERBV_INTERPOLATION_LINEARx001 :
2305 case GERBV_INTERPOLATION_LINEARx1 :
2306 g_message ("Object type: Line\n");
2307 break;
2308 case GERBV_INTERPOLATION_CW_CIRCULAR :
2309 case GERBV_INTERPOLATION_CCW_CIRCULAR :
2310 g_message ("Object type: Arc\n");
2311 break;
2312 default :
2313 g_message ("Object type: Unknown\n");
2314 break;
2316 g_message (" Exposure: On\n");
2317 if (validAperture) {
2318 g_message (" Aperture used: D%d\n", net->aperture);
2319 g_message (" Aperture type: %s\n", ap_names[ap_type]);
2321 g_message (" Start location: (%g, %g)\n", net->start_x, net->start_y);
2322 g_message (" Stop location: (%g, %g)\n", net->stop_x, net->stop_y);
2323 g_message (" Layer name: %s\n", layer_name);
2324 g_message (" Net label: %s\n", net_label);
2325 g_message (" In file: %s\n", mainProject->file[index]->name);
2326 break;
2327 case GERBV_APERTURE_STATE_FLASH:
2328 if (i!=0) g_message ("\n"); /* Spacing for a pretty display */
2329 g_message ("Object type: Flashed aperture\n");
2330 if (validAperture) {
2331 g_message (" Aperture used: D%d\n", net->aperture);
2332 g_message (" Aperture type: %s\n", ap_names[ap_type]);
2334 g_message (" Location: (%g, %g)\n", net->stop_x, net->stop_y);
2335 g_message (" Layer name: %s\n", layer_name);
2336 g_message (" Net label: %s\n", net_label);
2337 g_message (" In file: %s\n", mainProject->file[index]->name);
2338 break;
2341 g_free (net_label);
2342 g_free (layer_name);
2344 /* Use separator for different report requests */
2345 g_message ("---------------------------------------\n");
2348 void
2349 callbacks_support_benchmark (gerbv_render_info_t *renderInfo) {
2350 int i;
2351 time_t start, now;
2352 GdkPixmap *renderedPixmap = gdk_pixmap_new (NULL, renderInfo->displayWidth,
2353 renderInfo->displayHeight, 24);
2355 // start by running the GDK (fast) rendering test
2356 i = 0;
2357 start = time(NULL);
2358 now = start;
2359 while( now - 30 < start) {
2360 i++;
2361 dprintf("Benchmark(): Starting redraw #%d\n", i);
2362 gerbv_render_to_pixmap_using_gdk (mainProject, renderedPixmap, renderInfo, NULL, NULL);
2363 now = time(NULL);
2364 dprintf("Elapsed time = %ld seconds\n", (long int) (now - start));
2366 g_message("FAST mode benchmark: %d redraws in %ld seconds (%g redraws/second)\n",
2367 i, (long int) (now - start), (double) i / (double)(now - start));
2368 gdk_pixmap_unref(renderedPixmap);
2370 // run the cairo (normal) render mode
2371 i = 0;
2372 start = time(NULL);
2373 now = start;
2374 renderInfo->renderType = 2;
2375 while( now - 30 < start) {
2376 i++;
2377 dprintf("Benchmark(): Starting redraw #%d\n", i);
2378 cairo_surface_t *cSurface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
2379 renderInfo->displayWidth, renderInfo->displayHeight);
2380 cairo_t *cairoTarget = cairo_create (cSurface);
2381 gerbv_render_all_layers_to_cairo_target (mainProject, cairoTarget, renderInfo);
2382 cairo_destroy (cairoTarget);
2383 cairo_surface_destroy (cSurface);
2384 now = time(NULL);
2385 dprintf("Elapsed time = %ld seconds\n", (long int) (now - start));
2387 g_message("NORMAL mode benchmark: %d redraws in %ld seconds (%g redraws/second)\n",
2388 i, (long int) (now - start), (double) i / (double)(now - start));
2391 /* --------------------------------------------------------------------------- */
2392 void
2393 callbacks_benchmark_clicked (GtkButton *button, gpointer user_data)
2395 // prepare render size and options (canvas size width and height are last 2 variables)
2396 gerbv_render_info_t renderInfo = {1.0, 1.0, 0, 0, 0, 640, 480};
2397 // autoscale the image for now...maybe we don't want to do this in order to
2398 // allow benchmarking of different zoom levels?
2399 gerbv_render_zoom_to_fit_display (mainProject, &renderInfo);
2401 g_message("Full zoom benchmarks\n");
2402 callbacks_support_benchmark (&renderInfo);
2405 g_message("x5 zoom benchmarks\n");
2406 renderInfo.lowerLeftX += (screenRenderInfo.displayWidth /
2407 screenRenderInfo.scaleFactorX) / 3.0;
2408 renderInfo.lowerLeftY += (screenRenderInfo.displayHeight /
2409 screenRenderInfo.scaleFactorY) / 3.0;
2410 renderInfo.scaleFactorX *= 5;
2411 renderInfo.scaleFactorY *= 5;
2412 callbacks_support_benchmark (&renderInfo);
2415 /* --------------------------------------------------------------------------- */
2416 void
2417 callbacks_edit_object_properties_clicked (GtkButton *button, gpointer user_data){
2420 /* --------------------------------------------------------------------------- */
2421 void
2422 callbacks_move_objects_clicked (GtkButton *button, gpointer user_data){
2423 /* for testing, just hard code in some translations here */
2424 gerbv_image_move_selected_objects (screen.selectionInfo.selectedNodeArray, -0.050, 0.050);
2425 callbacks_update_layer_tree();
2426 render_clear_selection_buffer ();
2427 render_refresh_rendered_image_on_screen ();
2430 /* --------------------------------------------------------------------------- */
2431 void
2432 callbacks_reduce_object_area_clicked (GtkButton *button, gpointer user_data){
2433 /* for testing, just hard code in some parameters */
2434 gerbv_image_reduce_area_of_selected_objects (screen.selectionInfo.selectedNodeArray, 0.20, 3, 3, 0.01);
2435 render_clear_selection_buffer ();
2436 render_refresh_rendered_image_on_screen ();
2439 /* --------------------------------------------------------------------------- */
2440 void
2441 callbacks_delete_objects_clicked (GtkButton *button, gpointer user_data){
2442 if (screen.selectionInfo.type == GERBV_SELECTION_EMPTY) {
2443 interface_show_alert_dialog("No object is currently selected",
2444 "Objects must be selected using the pointer tool before they can be deleted.",
2445 FALSE,
2446 NULL);
2447 return;
2450 gint index=callbacks_get_selected_row_index();
2451 if (index < 0)
2452 return;
2454 if (mainProject->check_before_delete == TRUE) {
2455 if (!interface_get_alert_dialog_response(
2456 "Do you want to permanently delete the selected objects?",
2457 "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.",
2458 TRUE,
2459 &(mainProject->check_before_delete)))
2460 return;
2463 gerbv_image_delete_selected_nets (mainProject->file[index]->image,
2464 screen.selectionInfo.selectedNodeArray);
2465 render_refresh_rendered_image_on_screen ();
2466 /* Set layer_dirty flag to TRUE */
2467 mainProject->file[index]->layer_dirty = TRUE;
2468 callbacks_update_layer_tree();
2470 render_clear_selection_buffer ();
2471 callbacks_update_selected_object_message(FALSE);
2474 /* --------------------------------------------------------------------------- */
2475 gboolean
2476 callbacks_drawingarea_configure_event (GtkWidget *widget, GdkEventConfigure *event)
2478 GdkDrawable *drawable = widget->window;
2480 gdk_drawable_get_size (drawable, &screenRenderInfo.displayWidth, &screenRenderInfo.displayHeight);
2482 /* set this up if cairo is compiled, since we may need to switch over to
2483 using the surface at any time */
2484 int x_off=0, y_off=0;
2485 GdkVisual *visual;
2487 if (GDK_IS_WINDOW(widget->window)) {
2488 /* query the window's backbuffer if it has one */
2489 GdkWindow *window = GDK_WINDOW(widget->window);
2490 gdk_window_get_internal_paint_info (window, &drawable, &x_off, &y_off);
2492 visual = gdk_drawable_get_visual (drawable);
2493 if (screen.windowSurface)
2494 cairo_surface_destroy ((cairo_surface_t *)
2495 screen.windowSurface);
2496 #ifdef WIN32
2497 cairo_t *cairoTarget = gdk_cairo_create (GDK_WINDOW(widget->window));
2499 screen.windowSurface = cairo_get_target (cairoTarget);
2500 /* increase surface reference by one so it isn't freed when the cairo_t
2501 is destroyed next */
2502 screen.windowSurface = cairo_surface_reference (screen.windowSurface);
2503 cairo_destroy (cairoTarget);
2504 #else
2505 screen.windowSurface = (gpointer) cairo_xlib_surface_create (GDK_DRAWABLE_XDISPLAY (drawable),
2506 GDK_DRAWABLE_XID (drawable),
2507 GDK_VISUAL_XVISUAL (visual),
2508 screenRenderInfo.displayWidth,
2509 screenRenderInfo.displayHeight);
2510 #endif
2511 /* if this is the first time, go ahead and call autoscale even if we don't
2512 have a model loaded */
2513 if ((screenRenderInfo.scaleFactorX < 0.001)||(screenRenderInfo.scaleFactorY < 0.001)) {
2514 gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
2516 render_refresh_rendered_image_on_screen();
2517 return TRUE;
2520 /* --------------------------------------------------------- */
2521 gboolean
2522 callbacks_drawingarea_expose_event (GtkWidget *widget, GdkEventExpose *event)
2524 if (screenRenderInfo.renderType < 2) {
2525 GdkPixmap *new_pixmap;
2526 GdkGC *gc = gdk_gc_new(widget->window);
2529 * Create a pixmap with default background
2531 new_pixmap = gdk_pixmap_new(widget->window,
2532 widget->allocation.width,
2533 widget->allocation.height,
2534 -1);
2536 gdk_gc_set_foreground(gc, &mainProject->background);
2538 gdk_draw_rectangle(new_pixmap, gc, TRUE,
2539 event->area.x, event->area.y,
2540 event->area.width, event->area.height);
2543 * Copy gerber pixmap onto background if we have one to copy.
2544 * Do translation at the same time.
2546 if (screen.pixmap != NULL) {
2547 gdk_draw_pixmap(new_pixmap,
2548 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
2549 screen.pixmap,
2550 event->area.x - screen.off_x,
2551 event->area.y - screen.off_y,
2552 event->area.x, event->area.y,
2553 event->area.width, event->area.height);
2557 * Draw the whole thing onto screen
2559 gdk_draw_pixmap(widget->window,
2560 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
2561 new_pixmap,
2562 event->area.x, event->area.y,
2563 event->area.x, event->area.y,
2564 event->area.width, event->area.height);
2566 gdk_pixmap_unref(new_pixmap);
2567 gdk_gc_unref(gc);
2570 * Draw Zooming outline if we are in that mode
2572 if (screen.state == IN_ZOOM_OUTLINE) {
2573 render_draw_zoom_outline(screen.centered_outline_zoom);
2575 else if (screen.state == IN_MEASURE) {
2576 render_draw_measure_distance();
2578 if (screen.tool == MEASURE && screen.state != IN_MEASURE) {
2579 render_toggle_measure_line();
2582 return FALSE;
2585 cairo_t *cr;
2586 int width, height;
2587 int x_off=0, y_off=0;
2588 GdkDrawable *drawable = widget->window;
2589 GdkVisual *visual;
2591 if (GDK_IS_WINDOW(widget->window)) {
2592 /* query the window's backbuffer if it has one */
2593 GdkWindow *window = GDK_WINDOW(widget->window);
2594 gdk_window_get_internal_paint_info (window,
2595 &drawable, &x_off, &y_off);
2597 visual = gdk_drawable_get_visual (drawable);
2598 gdk_drawable_get_size (drawable, &width, &height);
2600 #ifdef WIN32
2601 /* FIXME */
2602 cr = gdk_cairo_create (GDK_WINDOW(widget->window));
2603 #else
2604 cairo_surface_t *buffert;
2606 buffert = (gpointer) cairo_xlib_surface_create (GDK_DRAWABLE_XDISPLAY (drawable),
2607 GDK_DRAWABLE_XID (drawable),
2608 GDK_VISUAL_XVISUAL (visual),
2609 event->area.width, event->area.height);
2610 cr = cairo_create (buffert);
2611 #endif
2612 cairo_translate (cr, -event->area.x + screen.off_x, -event->area.y + screen.off_y);
2613 render_project_to_cairo_target (cr);
2614 cairo_destroy (cr);
2615 #ifndef WIN32
2616 cairo_surface_destroy (buffert);
2617 #endif
2619 if (screen.tool == MEASURE)
2620 render_toggle_measure_line();
2621 return FALSE;
2624 /* Transforms screen coordinates to board ones */
2625 static void
2626 callbacks_screen2board(gdouble *X, gdouble *Y, gint x, gint y) {
2628 /* make sure we don't divide by zero (which is possible if the gui
2629 isn't displayed yet */
2630 if ((screenRenderInfo.scaleFactorX > 0.001)||(screenRenderInfo.scaleFactorY > 0.001)) {
2631 *X = screenRenderInfo.lowerLeftX + (x / screenRenderInfo.scaleFactorX);
2632 *Y = screenRenderInfo.lowerLeftY + ((screenRenderInfo.displayHeight - y)
2633 / screenRenderInfo.scaleFactorY);
2635 else {
2636 *X = *Y = 0.0;
2640 /* --------------------------------------------------------- */
2641 void
2642 callbacks_update_statusbar_coordinates (gint x, gint y) {
2643 gdouble X, Y;
2645 callbacks_screen2board(&X, &Y, x, y);
2646 if (screen.unit == GERBV_MILS) {
2647 snprintf(screen.statusbar.coordstr, MAX_COORDLEN,
2648 "(%8.2f, %8.2f)",
2649 COORD2MILS(X), COORD2MILS(Y));
2650 } else if (screen.unit == GERBV_MMS) {
2651 snprintf(screen.statusbar.coordstr, MAX_COORDLEN,
2652 "(%8.3f, %8.3f)",
2653 COORD2MMS(X), COORD2MMS(Y));
2654 } else {
2655 snprintf(screen.statusbar.coordstr, MAX_COORDLEN,
2656 "(%4.5f, %4.5f)",
2657 COORD2MILS(X) / 1000.0, COORD2MILS(Y) / 1000.0);
2659 callbacks_update_statusbar();
2662 void
2663 callbacks_update_selected_object_message (gboolean userTriedToSelect) {
2664 if (screen.tool != POINTER)
2665 return;
2667 gint selectionLength = screen.selectionInfo.selectedNodeArray->len;
2668 if ((selectionLength == 0)&&(userTriedToSelect)) {
2669 /* update status bar message to make sure the user knows
2670 about needing to select the layer */
2671 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2672 "<b>No object selected. Objects can only be selected in the active layer.</b>");
2674 else if (selectionLength == 0) {
2675 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2676 "Click to select objects in the current layer. Middle click and drag to pan.");
2678 else if (selectionLength == 1) {
2679 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2680 "1 object is currently selected");
2682 else {
2683 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2684 "%d objects are currently selected",selectionLength);
2686 callbacks_update_statusbar();
2689 /* --------------------------------------------------------- */
2690 gboolean
2691 callbacks_drawingarea_motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
2693 int x, y;
2694 GdkModifierType state;
2696 if (event->is_hint)
2697 gdk_window_get_pointer (event->window, &x, &y, &state);
2698 else {
2699 x = event->x;
2700 y = event->y;
2701 state = event->state;
2704 switch (screen.state) {
2705 case IN_MOVE: {
2706 if (screen.last_x != 0 || screen.last_y != 0) {
2707 /* Move pixmap to get a snappier feel of movement */
2708 screen.off_x += x - screen.last_x;
2709 screen.off_y += y - screen.last_y;
2711 screenRenderInfo.lowerLeftX -= ((x - screen.last_x) / screenRenderInfo.scaleFactorX);
2712 screenRenderInfo.lowerLeftY += ((y - screen.last_y) / screenRenderInfo.scaleFactorY);
2713 callbacks_force_expose_event_for_screen ();
2714 callbacks_update_scrollbar_positions ();
2715 screen.last_x = x;
2716 screen.last_y = y;
2717 break;
2719 case IN_ZOOM_OUTLINE: {
2720 if (screen.last_x || screen.last_y)
2721 render_draw_zoom_outline(screen.centered_outline_zoom);
2722 screen.last_x = x;
2723 screen.last_y = y;
2724 render_draw_zoom_outline(screen.centered_outline_zoom);
2725 break;
2727 case IN_MEASURE: {
2728 /* clear the previous drawn line by drawing over it */
2729 render_toggle_measure_line();
2730 callbacks_screen2board(&(screen.measure_last_x), &(screen.measure_last_y),
2731 x, y);
2732 /* screen.last_[xy] are updated to move the ruler pointers */
2733 screen.last_x = x;
2734 screen.last_y = y;
2735 /* draw the new line and write the new distance */
2736 render_draw_measure_distance();
2737 break;
2739 case IN_SELECTION_DRAG: {
2740 if (screen.last_x || screen.last_y)
2741 render_draw_selection_box_outline();
2742 screen.last_x = x;
2743 screen.last_y = y;
2744 render_draw_selection_box_outline();
2745 break;
2747 default:
2748 screen.last_x = x;
2749 screen.last_y = y;
2750 break;
2752 callbacks_update_statusbar_coordinates (x, y);
2753 callbacks_update_ruler_pointers ();
2754 return TRUE;
2755 } /* motion_notify_event */
2757 /* --------------------------------------------------------- */
2758 gboolean
2759 callbacks_drawingarea_button_press_event (GtkWidget *widget, GdkEventButton *event)
2761 GdkCursor *cursor;
2763 switch (event->button) {
2764 case 1 :
2765 if (screen.tool == POINTER) {
2766 /* select */
2767 /* selection will only work with cairo, so do nothing if it's
2768 not compiled */
2769 screen.state = IN_SELECTION_DRAG;
2770 screen.start_x = event->x;
2771 screen.start_y = event->y;
2773 else if (screen.tool == PAN) {
2774 /* Plain panning */
2775 screen.state = IN_MOVE;
2776 screen.last_x = event->x;
2777 screen.last_y = event->y;
2779 else if (screen.tool == ZOOM) {
2780 screen.state = IN_ZOOM_OUTLINE;
2781 /* Zoom outline mode initiated */
2782 screen.start_x = event->x;
2783 screen.start_y = event->y;
2784 screen.centered_outline_zoom = event->state;
2786 else if (screen.tool == MEASURE) {
2787 screen.state = IN_MEASURE;
2788 callbacks_screen2board(&(screen.measure_start_x), &(screen.measure_start_y),
2789 event->x, event->y);
2790 screen.measure_last_x = screen.measure_start_x;
2791 screen.measure_last_y = screen.measure_start_y;
2792 /* force an expose event to clear any previous measure lines */
2793 callbacks_force_expose_event_for_screen ();
2795 break;
2796 case 2 :
2797 screen.state = IN_MOVE;
2798 screen.last_x = event->x;
2799 screen.last_y = event->y;
2800 cursor = gdk_cursor_new(GDK_FLEUR);
2801 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
2802 cursor);
2803 gdk_cursor_destroy(cursor);
2804 break;
2805 case 3 :
2806 if (screen.tool == POINTER) {
2807 /* if no items are selected, try and find the item the user
2808 is pointing at */
2809 if (screen.selectionInfo.type == GERBV_SELECTION_EMPTY) {
2810 gint index=callbacks_get_selected_row_index();
2811 if ((index >= 0) &&
2812 (index <= mainProject->last_loaded) &&
2813 (mainProject->file[index]->isVisible)) {
2814 render_fill_selection_buffer_from_mouse_click(event->x,event->y,index,TRUE);
2815 } else {
2816 render_clear_selection_buffer ();
2817 render_refresh_rendered_image_on_screen ();
2820 /* only show the popup if we actually have something selected now */
2821 if (screen.selectionInfo.type != GERBV_SELECTION_EMPTY)
2822 gtk_menu_popup(GTK_MENU(screen.win.drawWindowPopupMenu), NULL, NULL, NULL, NULL,
2823 event->button, event->time);
2824 } else {
2825 /* Zoom outline mode initiated */
2826 screen.state = IN_ZOOM_OUTLINE;
2827 screen.start_x = event->x;
2828 screen.start_y = event->y;
2829 screen.centered_outline_zoom = event->state & GDK_SHIFT_MASK;
2830 cursor = gdk_cursor_new(GDK_SIZING);
2831 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window),
2832 cursor);
2833 gdk_cursor_destroy(cursor);
2835 break;
2836 case 4 : /* Scroll wheel */
2837 render_zoom_display (ZOOM_IN_CMOUSE, 0, event->x, event->y);
2838 break;
2839 case 5 : /* Scroll wheel */
2840 render_zoom_display (ZOOM_OUT_CMOUSE, 0, event->x, event->y);
2841 break;
2842 default:
2843 break;
2845 callbacks_switch_to_correct_cursor ();
2846 return TRUE;
2849 /* --------------------------------------------------------- */
2850 gboolean
2851 callbacks_drawingarea_button_release_event (GtkWidget *widget, GdkEventButton *event)
2853 if (event->type == GDK_BUTTON_RELEASE) {
2854 if (screen.state == IN_MOVE) {
2855 screen.off_x = 0;
2856 screen.off_y = 0;
2857 render_refresh_rendered_image_on_screen();
2858 callbacks_switch_to_normal_tool_cursor (screen.tool);
2860 else if (screen.state == IN_ZOOM_OUTLINE) {
2861 if ((event->state & GDK_SHIFT_MASK) != 0) {
2862 render_zoom_display (ZOOM_OUT_CMOUSE, 0, event->x, event->y);
2864 /* if the user just clicks without dragging, then simply
2865 zoom in a preset amount */
2866 else if ((abs(screen.start_x - event->x) < 4) &&
2867 (abs(screen.start_y - event->y) < 4)) {
2868 render_zoom_display (ZOOM_IN_CMOUSE, 0, event->x, event->y);
2870 else
2871 render_calculate_zoom_from_outline (widget, event);
2872 callbacks_switch_to_normal_tool_cursor (screen.tool);
2874 else if (screen.state == IN_SELECTION_DRAG) {
2875 /* selection will only work with cairo, so do nothing if it's
2876 not compiled */
2877 gint index=callbacks_get_selected_row_index();
2878 /* determine if this was just a click or a box drag */
2879 if ((index >= 0) &&
2880 (mainProject->file[index]->isVisible)) {
2881 gboolean eraseOldSelection = TRUE;
2883 if ((event->state & GDK_SHIFT_MASK) ||
2884 (event->state & GDK_CONTROL_MASK)) {
2885 eraseOldSelection = FALSE;
2887 if ((fabs((double)(screen.last_x - screen.start_x)) < 5) &&
2888 (fabs((double)(screen.last_y - screen.start_y)) < 5))
2889 render_fill_selection_buffer_from_mouse_click(event->x,event->y,index,eraseOldSelection);
2890 else
2891 render_fill_selection_buffer_from_mouse_drag(event->x,event->y,
2892 screen.start_x,screen.start_y,index,eraseOldSelection);
2893 /* check if anything was selected */
2894 callbacks_update_selected_object_message (TRUE);
2895 } else {
2896 render_clear_selection_buffer ();
2897 render_refresh_rendered_image_on_screen ();
2900 screen.last_x = screen.last_y = 0;
2901 screen.state = NORMAL;
2903 return TRUE;
2904 } /* button_release_event */
2906 /* --------------------------------------------------------- */
2907 gboolean
2908 callbacks_window_key_press_event (GtkWidget *widget, GdkEventKey *event)
2910 switch(event->keyval) {
2911 case GDK_Escape:
2912 if (screen.tool == POINTER) {
2913 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2914 "No objects are currently selected");
2915 callbacks_update_statusbar();
2916 render_clear_selection_buffer ();
2918 break;
2919 default:
2920 break;
2923 /* Escape may be used to abort outline zoom and just plain repaint */
2924 if (event->keyval == GDK_Escape) {
2925 screen.state = NORMAL;
2926 render_refresh_rendered_image_on_screen();
2929 return TRUE;
2930 } /* key_press_event */
2932 /* --------------------------------------------------------- */
2933 gboolean
2934 callbacks_window_key_release_event (GtkWidget *widget, GdkEventKey *event)
2936 return TRUE;
2937 } /* key_release_event */
2939 /* --------------------------------------------------------- */
2940 /* Scroll wheel */
2941 gboolean
2942 callbacks_window_scroll_event(GtkWidget *widget, GdkEventScroll *event)
2944 switch (event->direction) {
2945 case GDK_SCROLL_UP:
2946 render_zoom_display (ZOOM_IN_CMOUSE, 0, event->x, event->y);
2947 break;
2948 case GDK_SCROLL_DOWN:
2949 render_zoom_display (ZOOM_OUT_CMOUSE, 0, event->x, event->y);
2950 break;
2951 case GDK_SCROLL_LEFT:
2952 /* Ignore */
2953 case GDK_SCROLL_RIGHT:
2954 /* Ignore */
2955 default:
2956 return TRUE;
2958 return TRUE;
2959 } /* scroll_event */
2962 /* ------------------------------------------------------------------ */
2963 /** Displays additional information in the statusbar.
2964 The Statusbar is divided into three sections:\n
2965 statusbar.coordstr for coords\n
2966 statusbar.diststr for displaying measured distances or the designator
2967 (right click on a graphically marked and also actively selected part)\n
2968 statusbar.msg for e.g. showing progress of actions*/
2969 void
2970 callbacks_update_statusbar(void)
2972 if ((screen.statusbar.coordstr != NULL)&&(GTK_IS_LABEL(screen.win.statusMessageLeft))) {
2973 gtk_label_set_text(GTK_LABEL(screen.win.statusMessageLeft), screen.statusbar.coordstr);
2975 if ((screen.statusbar.diststr != NULL)&&(GTK_IS_LABEL(screen.win.statusMessageRight))) {
2976 gtk_label_set_markup(GTK_LABEL(screen.win.statusMessageRight), screen.statusbar.diststr);
2980 /* --------------------------------------------------------- */
2981 void
2982 callbacks_update_statusbar_measured_distance (gdouble dx, gdouble dy){
2983 gdouble delta = sqrt(dx*dx + dy*dy);
2985 if (screen.unit == GERBV_MILS) {
2986 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2987 "Measured distance: %8.2f mils (%8.2f x, %8.2f y)",
2988 COORD2MILS(delta), COORD2MILS(dx), COORD2MILS(dy));
2990 else if (screen.unit == GERBV_MMS) {
2991 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2992 "Measured distance: %8.3f mms (%8.3f x, %8.3f y)",
2993 COORD2MMS(delta), COORD2MMS(dx), COORD2MMS(dy));
2995 else {
2996 snprintf(screen.statusbar.diststr, MAX_DISTLEN,
2997 "Measured distance: %4.5f inches (%4.5f x, %4.5f y)",
2998 COORD2MILS(delta) / 1000.0, COORD2MILS(dx) / 1000.0,
2999 COORD2MILS(dy) / 1000.0);
3001 callbacks_update_statusbar();
3004 /* --------------------------------------------------------- */
3005 void
3006 callbacks_sidepane_render_type_combo_box_changed (GtkComboBox *widget, gpointer user_data) {
3007 int activeRow = gtk_combo_box_get_active (widget);
3009 dprintf ("%s(): activeRow = %d\n", __FUNCTION__, activeRow);
3010 screenRenderInfo.renderType = activeRow;
3012 render_refresh_rendered_image_on_screen();
3015 /* --------------------------------------------------------- */
3016 void
3017 callbacks_statusbar_unit_combo_box_changed (GtkComboBox *widget, gpointer user_data) {
3018 int activeRow = gtk_combo_box_get_active (widget);
3020 if (activeRow >= 0) {
3021 screen.unit = activeRow;
3023 callbacks_update_ruler_scales();
3024 callbacks_update_statusbar_coordinates (screen.last_x, screen.last_y);
3026 if (screen.tool == MEASURE)
3027 callbacks_update_statusbar_measured_distance (screen.win.lastMeasuredX,
3028 screen.win.lastMeasuredY);
3031 /* --------------------------------------------------------- */
3032 void
3033 callbacks_clear_messages_button_clicked (GtkButton *button, gpointer user_data) {
3034 GtkTextBuffer *textbuffer;
3035 GtkTextIter start, end;
3037 textbuffer = gtk_text_view_get_buffer((GtkTextView*)screen.win.messageTextView);
3038 gtk_text_buffer_get_start_iter(textbuffer, &start);
3039 gtk_text_buffer_get_end_iter(textbuffer, &end);
3040 gtk_text_buffer_delete (textbuffer, &start, &end);
3043 /* --------------------------------------------------------- */
3044 void
3045 callbacks_handle_log_messages(const gchar *log_domain, GLogLevelFlags log_level,
3046 const gchar *message, gpointer user_data) {
3047 GtkTextBuffer *textbuffer = NULL;
3048 GtkTextIter iter;
3049 GtkTextTag *tag;
3050 GtkTextMark *StartMark = NULL, *StopMark = NULL;
3051 GtkTextIter StartIter, StopIter;
3053 if (!screen.win.messageTextView)
3054 return;
3056 textbuffer = gtk_text_view_get_buffer((GtkTextView*)screen.win.messageTextView);
3058 /* create a mark for the end of the text. */
3059 gtk_text_buffer_get_end_iter(textbuffer, &iter);
3061 /* get the current end position of the text (it will be the
3062 start of the new text. */
3063 StartMark = gtk_text_buffer_create_mark(textbuffer,
3064 "NewTextStart", &iter, TRUE);
3066 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3067 "blue_foreground");
3068 /* the tag does not exist: create it and let them exist in the tag table.*/
3069 if (tag == NULL) {
3070 tag = gtk_text_buffer_create_tag(textbuffer, "black_foreground",
3071 "foreground", "black", NULL);
3072 tag = gtk_text_buffer_create_tag(textbuffer, "blue_foreground",
3073 "foreground", "blue", NULL);
3074 tag = gtk_text_buffer_create_tag(textbuffer, "red_foreground",
3075 "foreground", "red", NULL);
3076 tag = gtk_text_buffer_create_tag(textbuffer, "darkred_foreground",
3077 "foreground", "darkred", NULL);
3078 tag = gtk_text_buffer_create_tag(textbuffer, "darkblue_foreground",
3079 "foreground", "darkblue", NULL);
3080 tag = gtk_text_buffer_create_tag (textbuffer, "darkgreen_foreground",
3081 "foreground", "darkgreen", NULL);
3082 tag = gtk_text_buffer_create_tag (textbuffer,
3083 "saddlebrown_foreground",
3084 "foreground", "saddlebrown", NULL);
3088 * See rgb.txt for the color names definition
3089 * (on my PC it is on /usr/X11R6/lib/X11/rgb.txt)
3091 switch (log_level & G_LOG_LEVEL_MASK) {
3092 case G_LOG_LEVEL_ERROR:
3093 /* a message of this kind aborts the application calling abort() */
3094 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3095 "red_foreground");
3096 gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
3097 gtk_widget_show(screen.win.sidepane_notebook);
3098 break;
3099 case G_LOG_LEVEL_CRITICAL:
3100 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3101 "red_foreground");
3102 gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
3103 gtk_widget_show(screen.win.sidepane_notebook);
3104 break;
3105 case G_LOG_LEVEL_WARNING:
3106 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3107 "darkred_foreground");
3108 gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
3109 gtk_widget_show(screen.win.sidepane_notebook);
3110 break;
3111 case G_LOG_LEVEL_MESSAGE:
3112 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3113 "darkblue_foreground");
3114 gtk_notebook_set_current_page(GTK_NOTEBOOK(screen.win.sidepane_notebook), 1);
3115 gtk_widget_show(screen.win.sidepane_notebook);
3116 break;
3117 case G_LOG_LEVEL_INFO:
3118 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3119 "darkgreen_foreground");
3120 break;
3121 case G_LOG_LEVEL_DEBUG:
3122 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textbuffer),
3123 "saddlebrown_foreground");
3124 break;
3125 default:
3126 tag = gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table(textbuffer),
3127 "black_foreground");
3128 break;
3132 * Fatal aborts application. We will try to get the message out anyhow.
3134 if (log_level & G_LOG_FLAG_FATAL)
3135 fprintf(stderr, "Fatal error : %s\n", message);
3137 gtk_text_buffer_insert(textbuffer, &iter, message, -1);
3139 gtk_text_buffer_get_end_iter(textbuffer, &iter);
3141 StopMark = gtk_text_buffer_create_mark(textbuffer,
3142 "NewTextStop", &iter, TRUE);
3144 gtk_text_buffer_get_iter_at_mark(textbuffer, &StartIter, StartMark);
3145 gtk_text_buffer_get_iter_at_mark(textbuffer, &StopIter, StopMark);
3147 gtk_text_buffer_apply_tag(textbuffer, tag, &StartIter, &StopIter);
3150 /* --------------------------------------------------------- */
3151 void callbacks_force_expose_event_for_screen (void){
3153 GdkRectangle update_rect;
3155 update_rect.x = 0;
3156 update_rect.y = 0;
3157 update_rect.width = screenRenderInfo.displayWidth;
3158 update_rect.height = screenRenderInfo.displayHeight;
3160 /* Calls expose_event */
3161 gdk_window_invalidate_rect (screen.drawing_area->window, &update_rect, FALSE);
3163 /* update other gui things that could have changed */
3164 callbacks_update_ruler_scales();
3165 callbacks_update_scrollbar_limits();
3166 callbacks_update_scrollbar_positions();