Fix lockup when a scroll event is received outside the drawing area
[geda-pcb/pcjc2.git] / src / hid / gtk / gui-top-window.c
blobba62d52066a35c091c986a7d3123c9658bb8b1d0
1 /*
2 * COPYRIGHT
4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 /* #define DEBUG_MENUS */
25 #ifdef DAN_FIXME
26 TODO:
28 - figure out when we need to call this:
29 ghid_set_status_line_label ();
30 Everytime?
32 - the old quit callback had:
34 ghid_config_files_write ();
35 hid_action ("Quit");
37 - what about stuff like this:
39 /* Set to ! because ActionDisplay toggles it */
40 Settings.DrawGrid = !gtk_toggle_action_get_active (action);
41 ghidgui->config_modified = TRUE;
42 hid_actionl ("Display", "Grid", "", NULL);
43 ghid_set_status_line_label ();
46 I NEED TO DO THE STATUS LINE THING. for example shift-alt-v to change the
47 via size. NOte the status line label does not get updated properly until
48 a zoom in/out.
50 #endif
52 /* This file was originally written by Bill Wilson for the PCB Gtk
53 * port. It was later heavily modified by Dan McMahill to provide
54 * user customized menus.
58 /* gui-top-window.c
59 | This handles creation of the top level window and all its widgets.
60 | events for the Output.drawing_area widget are handled in a separate
61 | file gui-output-events.c
63 | Some caveats with menu shorcut keys: Some keys are trapped out by Gtk
64 | and can't be used as shortcuts (eg. '|', TAB, etc). For these cases
65 | we have our own shortcut table and capture the keys and send the events
66 | there in ghid_port_key_press_cb().
70 #ifdef HAVE_CONFIG_H
71 #include "config.h"
72 #endif
74 #include <unistd.h>
76 #ifdef HAVE_LOCALE_H
77 #include <locale.h>
78 #endif
80 #include "ghid-layer-selector.h"
81 #include "ghid-route-style-selector.h"
82 #include "gtkhid.h"
83 #include "gui.h"
84 #include "hid.h"
85 #include "../hidint.h"
86 #include "hid/common/hid_resource.h"
88 #include "action.h"
89 #include "autoplace.h"
90 #include "autoroute.h"
91 #include "buffer.h"
92 #include "change.h"
93 #include "command.h"
94 #include "copy.h"
95 #include "create.h"
96 #include "crosshair.h"
97 #include "draw.h"
98 #include "error.h"
99 #include "file.h"
100 #include "find.h"
101 #include "gpcb-menu.h"
102 #include "insert.h"
103 #include "line.h"
104 #include "mymem.h"
105 #include "misc.h"
106 #include "move.h"
107 #include "pcb-printf.h"
108 #include "polygon.h"
109 #include "rats.h"
110 #include "remove.h"
111 #include "report.h"
112 #include "resource.h"
113 #include "rotate.h"
114 #include "rubberband.h"
115 #include "search.h"
116 #include "select.h"
117 #include "set.h"
118 #include "undo.h"
119 #include "vendor.h"
120 #include "free_atexit.h"
122 #include "gui-icons-mode-buttons.data"
123 #include "gui-icons-misc.data"
124 #include "gui-trackball.h"
126 #ifdef HAVE_LIBDMALLOC
127 #include <dmalloc.h>
128 #endif
130 static bool ignore_layer_update;
132 static GtkWidget *ghid_load_menus (void);
134 GhidGui _ghidgui, *ghidgui = NULL;
136 GHidPort ghid_port, *gport;
138 static gchar *bg_image_file;
140 static struct { GtkAction *action; const Resource *node; }
141 ghid_hotkey_actions[256];
142 #define N_HOTKEY_ACTIONS \
143 (sizeof (ghid_hotkey_actions) / sizeof (ghid_hotkey_actions[0]))
146 /*! \brief callback for ghid_main_menu_update_toggle_state () */
147 void
148 menu_toggle_update_cb (GtkAction *act, const char *tflag, const char *aflag)
150 if (tflag != NULL)
152 int v = hid_get_flag (tflag);
153 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (act), !!v);
155 if (aflag != NULL)
157 int v = hid_get_flag (aflag);
158 gtk_action_set_sensitive (act, !!v);
162 /*! \brief sync the menu checkboxes with actual pcb state */
163 void
164 ghid_update_toggle_flags ()
166 ghid_main_menu_update_toggle_state (GHID_MAIN_MENU (ghidgui->menu_bar),
167 menu_toggle_update_cb);
170 static void
171 h_adjustment_changed_cb (GtkAdjustment * adj, GhidGui * g)
173 if (g->adjustment_changed_holdoff)
174 return;
176 ghid_port_ranges_changed ();
179 static void
180 v_adjustment_changed_cb (GtkAdjustment * adj, GhidGui * g)
182 if (g->adjustment_changed_holdoff)
183 return;
185 ghid_port_ranges_changed ();
188 /* Save size of top window changes so PCB can restart at its size at exit.
190 static gint
191 top_window_configure_event_cb (GtkWidget * widget, GdkEventConfigure * ev,
192 GHidPort * port)
194 GtkAllocation allocation;
195 gboolean new_w, new_h;
197 gtk_widget_get_allocation (widget, &allocation);
199 new_w = (ghidgui->top_window_width != allocation.width);
200 new_h = (ghidgui->top_window_height != allocation.height);
202 ghidgui->top_window_width = allocation.width;
203 ghidgui->top_window_height = allocation.height;
205 if (new_w || new_h)
206 ghidgui->config_modified = TRUE;
208 return FALSE;
211 static void
212 info_bar_response_cb (GtkInfoBar *info_bar,
213 gint response_id,
214 GhidGui *_gui)
216 gtk_widget_destroy (_gui->info_bar);
217 _gui->info_bar = NULL;
219 if (response_id == GTK_RESPONSE_ACCEPT)
220 RevertPCB ();
223 static void
224 close_file_modified_externally_prompt (void)
226 if (ghidgui->info_bar != NULL)
227 gtk_widget_destroy (ghidgui->info_bar);
228 ghidgui->info_bar = NULL;
231 static void
232 show_file_modified_externally_prompt (void)
234 GtkWidget *button;
235 GtkWidget *button_image;
236 GtkWidget *icon;
237 GtkWidget *label;
238 GtkWidget *content_area;
239 char *file_path_utf8;
240 char *secondary_text;
241 char *markup;
243 close_file_modified_externally_prompt ();
245 ghidgui->info_bar = gtk_info_bar_new ();
247 button = gtk_info_bar_add_button (GTK_INFO_BAR (ghidgui->info_bar),
248 _("Reload"),
249 GTK_RESPONSE_ACCEPT);
250 button_image = gtk_image_new_from_stock (GTK_STOCK_REFRESH,
251 GTK_ICON_SIZE_BUTTON);
252 gtk_button_set_image (GTK_BUTTON (button), button_image);
254 gtk_info_bar_add_button (GTK_INFO_BAR (ghidgui->info_bar),
255 GTK_STOCK_CANCEL,
256 GTK_RESPONSE_CANCEL);
257 gtk_info_bar_set_message_type (GTK_INFO_BAR (ghidgui->info_bar),
258 GTK_MESSAGE_WARNING);
259 gtk_box_pack_start (GTK_BOX (ghidgui->vbox_middle),
260 ghidgui->info_bar, FALSE, FALSE, 0);
261 gtk_box_reorder_child (GTK_BOX (ghidgui->vbox_middle), ghidgui->info_bar, 0);
264 g_signal_connect (ghidgui->info_bar, "response",
265 G_CALLBACK (info_bar_response_cb), ghidgui);
267 file_path_utf8 = g_filename_to_utf8 (PCB->Filename, -1, NULL, NULL, NULL);
269 secondary_text = PCB->Changed ? _("Do you want to drop your changes and reload the file?") :
270 _("Do you want to reload the file?");
272 markup = g_markup_printf_escaped (_("<b>The file %s has changed on disk</b>\n\n%s"),
273 file_path_utf8, secondary_text);
274 g_free (file_path_utf8);
276 content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (ghidgui->info_bar));
278 icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
279 GTK_ICON_SIZE_DIALOG);
280 gtk_box_pack_start (GTK_BOX (content_area),
281 icon, FALSE, FALSE, 0);
283 label = gtk_label_new ("");
284 gtk_box_pack_start (GTK_BOX (content_area),
285 label, TRUE, TRUE, 6);
287 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
288 gtk_label_set_markup (GTK_LABEL (label), markup);
289 g_free (markup);
291 gtk_misc_set_alignment (GTK_MISC (label), 0., 0.5);
293 gtk_widget_show_all (ghidgui->info_bar);
296 static bool
297 check_externally_modified (void)
299 GFile *file;
300 GFileInfo *info;
301 GTimeVal timeval;
303 /* Treat zero time as a flag to indicate we've not got an mtime yet */
304 if (PCB->Filename == NULL ||
305 (ghidgui->our_mtime.tv_sec == 0 &&
306 ghidgui->our_mtime.tv_usec == 0))
307 return false;
309 file = g_file_new_for_path (PCB->Filename);
310 info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED,
311 G_FILE_QUERY_INFO_NONE, NULL, NULL);
312 g_object_unref (file);
314 if (info == NULL ||
315 !g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED))
316 return false;
318 g_file_info_get_modification_time (info, &timeval); //&ghidgui->last_seen_mtime);
319 g_object_unref (info);
321 /* Ignore when the file on disk is the same age as when we last looked */
322 if (timeval.tv_sec == ghidgui->last_seen_mtime.tv_sec &&
323 timeval.tv_usec == ghidgui->last_seen_mtime.tv_usec)
324 return false;
326 ghidgui->last_seen_mtime = timeval;
328 return (ghidgui->last_seen_mtime.tv_sec > ghidgui->our_mtime.tv_sec) ||
329 (ghidgui->last_seen_mtime.tv_sec == ghidgui->our_mtime.tv_sec &&
330 ghidgui->last_seen_mtime.tv_usec > ghidgui->our_mtime.tv_usec);
333 static gboolean
334 top_window_enter_cb (GtkWidget *widget, GdkEvent *event, GHidPort *port)
336 if (check_externally_modified ())
337 show_file_modified_externally_prompt ();
339 return FALSE;
342 /*! \brief Menu action callback function
343 * \par Function Description
344 * This is the main menu callback function. The callback receives
345 * the original Resource pointer containing the HID actions to be
346 * executed.
348 * All hotkeys go through the menus which means they go through here.
349 * Some, such as tab, are caught by Gtk instead of passed here, so
350 * pcb calls this function directly through ghid_hotkey_cb() for them.
352 * \param [in] The action that was activated
353 * \param [in] The menu resource associated with the action
356 static void
357 ghid_menu_cb (GtkAction *action, const Resource *node)
359 int i;
361 if (action == NULL || node == NULL)
362 return;
364 for (i = 1; i < node->c; i++)
365 if (resource_type (node->v[i]) == 10)
367 #ifdef DEBUG_MENUS
368 printf (" %s\n", node->v[i].value);
369 #endif
370 hid_parse_actions (node->v[i].value);
373 /* Sync gui widgets with pcb state */
374 ghid_update_toggle_flags ();
375 ghid_mode_buttons_update ();
377 /* Sync gui status display with pcb state */
378 AdjustAttachedObjects ();
379 ghid_invalidate_all ();
380 ghid_window_set_name_label (PCB->Name);
381 ghid_set_status_line_label ();
384 /* \brief Accelerator callback for accelerators gtk tries to hide from us */
385 void ghid_hotkey_cb (int which)
387 if (ghid_hotkey_actions[which].action != NULL)
388 ghid_menu_cb (ghid_hotkey_actions[which].action,
389 (gpointer) ghid_hotkey_actions[which].node);
392 static void
393 update_board_mtime_from_disk (void)
395 GFile *file;
396 GFileInfo *info;
398 ghidgui->our_mtime.tv_sec = 0;
399 ghidgui->our_mtime.tv_usec = 0;
400 ghidgui->last_seen_mtime = ghidgui->our_mtime;
402 if (PCB->Filename == NULL)
403 return;
405 file = g_file_new_for_path (PCB->Filename);
406 info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED,
407 G_FILE_QUERY_INFO_NONE, NULL, NULL);
408 g_object_unref (file);
410 if (info == NULL ||
411 !g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED))
412 return;
414 g_file_info_get_modification_time (info, &ghidgui->our_mtime);
415 g_object_unref (info);
417 ghidgui->last_seen_mtime = ghidgui->our_mtime;
420 /* Sync toggle states that were saved with the layout and notify the
421 | config code to update Settings values it manages.
423 void
424 ghid_sync_with_new_layout (void)
426 pcb_use_route_style (&PCB->RouteStyle[0]);
427 ghid_route_style_selector_select_style
428 (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector),
429 &PCB->RouteStyle[0]);
431 ghid_config_handle_units_changed ();
433 ghid_window_set_name_label (PCB->Name);
434 ghid_set_status_line_label ();
435 close_file_modified_externally_prompt ();
436 update_board_mtime_from_disk ();
439 void
440 ghid_notify_save_pcb (const char *filename, bool done)
442 /* Do nothing if it is not the active PCB file that is being saved.
444 if (PCB->Filename == NULL || strcmp (filename, PCB->Filename) != 0)
445 return;
447 if (done)
448 update_board_mtime_from_disk ();
451 void
452 ghid_notify_filename_changed (void)
454 /* Pick up the mtime of the new PCB file */
455 update_board_mtime_from_disk ();
458 /* ---------------------------------------------------------------------------
460 * layer_process()
462 * Takes the index into the layers and produces the text string for
463 * the layer and if the layer is currently visible or not. This is
464 * used by a couple of functions.
467 static void
468 layer_process (gchar **color_string, char **text, int *set, int i)
470 int tmp;
471 char *tmps;
472 gchar *tmpc;
474 /* cheap hack to let users pass in NULL for either text or set if
475 * they don't care about the result
478 if (color_string == NULL)
479 color_string = &tmpc;
481 if (text == NULL)
482 text = &tmps;
484 if (set == NULL)
485 set = &tmp;
487 switch (i)
489 case LAYER_BUTTON_SILK:
490 *color_string = Settings.ElementColor;
491 *text = _( "silk");
492 *set = PCB->ElementOn;
493 break;
494 case LAYER_BUTTON_RATS:
495 *color_string = Settings.RatColor;
496 *text = _( "rat lines");
497 *set = PCB->RatOn;
498 break;
499 case LAYER_BUTTON_PINS:
500 *color_string = Settings.PinColor;
501 *text = _( "pins/pads");
502 *set = PCB->PinOn;
503 break;
504 case LAYER_BUTTON_VIAS:
505 *color_string = Settings.ViaColor;
506 *text = _( "vias");
507 *set = PCB->ViaOn;
508 break;
509 case LAYER_BUTTON_FARSIDE:
510 *color_string = Settings.InvisibleObjectsColor;
511 *text = _( "far side");
512 *set = PCB->InvisibleObjectsOn;
513 break;
514 case LAYER_BUTTON_MASK:
515 *color_string = Settings.MaskColor;
516 *text = _( "solder mask");
517 *set = TEST_FLAG (SHOWMASKFLAG, PCB);
518 break;
519 default: /* layers */
520 *color_string = Settings.LayerColor[i];
521 *text = (char *)UNKNOWN (PCB->Data->Layer[i].Name);
522 *set = PCB->Data->Layer[i].On;
523 break;
527 /*! \brief Callback for GHidLayerSelector layer selection */
528 static void
529 layer_selector_select_callback (GHidLayerSelector *ls, int layer, gpointer d)
531 ignore_layer_update = true;
532 /* Select Layer */
533 PCB->SilkActive = (layer == LAYER_BUTTON_SILK);
534 PCB->RatDraw = (layer == LAYER_BUTTON_RATS);
535 if (layer == LAYER_BUTTON_SILK)
537 PCB->ElementOn = true;
538 hid_action ("LayersChanged");
540 else if (layer == LAYER_BUTTON_RATS)
542 PCB->RatOn = true;
543 hid_action ("LayersChanged");
545 else if (layer < max_copper_layer)
546 ChangeGroupVisibility (layer, TRUE, true);
548 ignore_layer_update = false;
550 ghid_invalidate_all ();
553 /*! \brief Callback for GHidLayerSelector layer renaming */
554 static void
555 layer_selector_rename_callback (GHidLayerSelector *ls,
556 int layer_id,
557 char *new_name,
558 void *userdata)
560 LayerType *layer = LAYER_PTR (layer_id);
562 /* Check for a legal layer name - for now, allow anything non-empty */
563 if (new_name[0] == '\0')
564 return;
566 /* Don't bother if the name is identical to the current one */
567 if (strcmp (layer->Name, new_name) == 0)
568 return;
570 free (layer->Name);
571 layer->Name = strdup (new_name);
572 ghid_layer_buttons_update ();
573 if (!PCB->Changed)
575 SetChangedFlag (true);
576 ghid_window_set_name_label (PCB->Name);
580 /*! \brief Callback for GHidLayerSelector layer toggling */
581 static void
582 layer_selector_toggle_callback (GHidLayerSelector *ls, int layer, gpointer d)
584 gboolean redraw = FALSE;
585 gboolean active;
586 layer_process (NULL, NULL, &active, layer);
588 active = !active;
589 ignore_layer_update = true;
590 switch (layer)
592 case LAYER_BUTTON_SILK:
593 PCB->ElementOn = active;
594 PCB->Data->SILKLAYER.On = PCB->ElementOn;
595 PCB->Data->BACKSILKLAYER.On = PCB->ElementOn;
596 redraw = 1;
597 break;
598 case LAYER_BUTTON_RATS:
599 PCB->RatOn = active;
600 redraw = 1;
601 break;
602 case LAYER_BUTTON_PINS:
603 PCB->PinOn = active;
604 redraw |= (PCB->Data->ElementN != 0);
605 break;
606 case LAYER_BUTTON_VIAS:
607 PCB->ViaOn = active;
608 redraw |= (PCB->Data->ViaN != 0);
609 break;
610 case LAYER_BUTTON_FARSIDE:
611 PCB->InvisibleObjectsOn = active;
612 PCB->Data->BACKSILKLAYER.On = (active && PCB->ElementOn);
613 redraw = TRUE;
614 break;
615 case LAYER_BUTTON_MASK:
616 if (active)
617 SET_FLAG (SHOWMASKFLAG, PCB);
618 else
619 CLEAR_FLAG (SHOWMASKFLAG, PCB);
620 redraw = TRUE;
621 break;
622 default:
623 /* Flip the visibility */
624 ChangeGroupVisibility (layer, active, false);
625 redraw = TRUE;
626 break;
629 /* Select the next visible layer. (If there is none, this will
630 * select the currently-selected layer, triggering the selection
631 * callback, which will turn the visibility on.) This way we
632 * will never have an invisible layer selected.
634 if (!active)
635 ghid_layer_selector_select_next_visible (ls);
637 ignore_layer_update = false;
639 if (redraw)
640 ghid_invalidate_all();
643 /*! \brief Install menu bar and accelerator groups */
644 void
645 ghid_install_accel_groups (GtkWindow *window, GhidGui *gui)
647 gtk_window_add_accel_group
648 (window, ghid_main_menu_get_accel_group
649 (GHID_MAIN_MENU (gui->menu_bar)));
650 gtk_window_add_accel_group
651 (window, ghid_layer_selector_get_accel_group
652 (GHID_LAYER_SELECTOR (gui->layer_selector)));
653 gtk_window_add_accel_group
654 (window, ghid_route_style_selector_get_accel_group
655 (GHID_ROUTE_STYLE_SELECTOR (gui->route_style_selector)));
658 /*! \brief Remove menu bar and accelerator groups */
659 void
660 ghid_remove_accel_groups (GtkWindow *window, GhidGui *gui)
662 gtk_window_remove_accel_group
663 (window, ghid_main_menu_get_accel_group
664 (GHID_MAIN_MENU (gui->menu_bar)));
665 gtk_window_remove_accel_group
666 (window, ghid_layer_selector_get_accel_group
667 (GHID_LAYER_SELECTOR (gui->layer_selector)));
668 gtk_window_remove_accel_group
669 (window, ghid_route_style_selector_get_accel_group
670 (GHID_ROUTE_STYLE_SELECTOR (gui->route_style_selector)));
673 /* Refreshes the window title bar and sets the PCB name to the
674 * window title bar or to a seperate label
676 void
677 ghid_window_set_name_label (gchar * name)
679 gchar *str;
680 gchar *filename;
682 /* FIXME -- should this happen? It does... */
683 /* This happens if we're calling an exporter from the command line */
684 if (ghidgui == NULL)
685 return;
687 dup_string (&(ghidgui->name_label_string), name);
688 if (!ghidgui->name_label_string || !*ghidgui->name_label_string)
689 ghidgui->name_label_string = g_strdup (_("Unnamed"));
691 if (!PCB->Filename || !*PCB->Filename)
692 filename = g_strdup(_("Unsaved.pcb"));
693 else
694 filename = g_strdup(PCB->Filename);
696 str = g_strdup_printf ("%s%s (%s) - PCB", PCB->Changed ? "*": "",
697 ghidgui->name_label_string, filename);
698 gtk_window_set_title (GTK_WINDOW (gport->top_window), str);
699 g_free (str);
700 g_free (filename);
703 static void
704 grid_units_button_cb (GtkWidget * widget, gpointer data)
706 /* Button only toggles between mm and mil */
707 if (Settings.grid_unit == get_unit_struct ("mm"))
708 hid_actionl ("SetUnits", "mil", NULL);
709 else
710 hid_actionl ("SetUnits", "mm", NULL);
714 * The two following callbacks are used to keep the absolute
715 * and relative cursor labels from growing and shrinking as you
716 * move the cursor around.
718 static void
719 absolute_label_size_req_cb (GtkWidget * widget,
720 GtkRequisition *req, gpointer data)
723 static gint w = 0;
724 if (req->width > w)
725 w = req->width;
726 else
727 req->width = w;
730 static void
731 relative_label_size_req_cb (GtkWidget * widget,
732 GtkRequisition *req, gpointer data)
735 static gint w = 0;
736 if (req->width > w)
737 w = req->width;
738 else
739 req->width = w;
742 static void
743 make_cursor_position_labels (GtkWidget * hbox, GHidPort * port)
745 GtkWidget *frame, *label;
747 /* The grid units button next to the cursor position labels.
749 ghidgui->grid_units_button = gtk_button_new ();
750 label = gtk_label_new ("");
751 gtk_label_set_markup (GTK_LABEL (label),
752 Settings.grid_unit->in_suffix);
753 ghidgui->grid_units_label = label;
754 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
755 gtk_container_add (GTK_CONTAINER (ghidgui->grid_units_button), label);
756 gtk_box_pack_end (GTK_BOX (hbox), ghidgui->grid_units_button, FALSE, TRUE, 0);
757 g_signal_connect (ghidgui->grid_units_button, "clicked",
758 G_CALLBACK (grid_units_button_cb), NULL);
760 /* The absolute cursor position label
762 frame = gtk_frame_new (NULL);
763 gtk_box_pack_end (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
764 gtk_container_set_border_width (GTK_CONTAINER (frame), 2);
765 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
767 label = gtk_label_new ("");
768 gtk_container_add (GTK_CONTAINER (frame), label);
769 ghidgui->cursor_position_absolute_label = label;
770 g_signal_connect (G_OBJECT (label), "size-request",
771 G_CALLBACK (absolute_label_size_req_cb), NULL);
774 /* The relative cursor position label
776 frame = gtk_frame_new (NULL);
777 gtk_box_pack_end (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
778 gtk_container_set_border_width (GTK_CONTAINER (frame), 2);
779 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
780 label = gtk_label_new (" __.__ __.__ ");
781 gtk_container_add (GTK_CONTAINER (frame), label);
782 ghidgui->cursor_position_relative_label = label;
783 g_signal_connect (G_OBJECT (label), "size-request",
784 G_CALLBACK (relative_label_size_req_cb), NULL);
788 /* \brief Add "virtual layers" to a layer selector */
789 static void
790 make_virtual_layer_buttons (GtkWidget *layer_selector)
792 GHidLayerSelector *layersel = GHID_LAYER_SELECTOR (layer_selector);
793 gchar *text;
794 gchar *color_string;
795 gboolean active;
797 layer_process (&color_string, &text, &active, LAYER_BUTTON_SILK);
798 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_SILK,
799 text, color_string, active, TRUE, FALSE);
800 layer_process (&color_string, &text, &active, LAYER_BUTTON_RATS);
801 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_RATS,
802 text, color_string, active, TRUE, FALSE);
803 layer_process (&color_string, &text, &active, LAYER_BUTTON_PINS);
804 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_PINS,
805 text, color_string, active, FALSE, FALSE);
806 layer_process (&color_string, &text, &active, LAYER_BUTTON_VIAS);
807 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_VIAS,
808 text, color_string, active, FALSE, FALSE);
809 layer_process (&color_string, &text, &active, LAYER_BUTTON_FARSIDE);
810 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_FARSIDE,
811 text, color_string, active, FALSE, FALSE);
812 layer_process (&color_string, &text, &active, LAYER_BUTTON_MASK);
813 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_MASK,
814 text, color_string, active, FALSE, FALSE);
817 /*! \brief callback for ghid_layer_selector_update_colors */
818 const gchar *
819 get_layer_color (gint layer)
821 gchar *rv;
822 layer_process (&rv, NULL, NULL, layer);
823 return rv;
826 /*! \brief Update a layer selector's color scheme */
827 void
828 ghid_layer_buttons_color_update (void)
830 ghid_layer_selector_update_colors
831 (GHID_LAYER_SELECTOR (ghidgui->layer_selector), get_layer_color);
832 pcb_colors_from_settings (PCB);
835 /*! \brief Populate a layer selector with all layers Gtk is aware of */
836 static void
837 make_layer_buttons (GtkWidget *layersel)
839 gint i;
840 gchar *text;
841 gchar *color_string;
842 gboolean active = TRUE;
844 for (i = 0; i < max_copper_layer; ++i)
846 layer_process (&color_string, &text, &active, i);
847 ghid_layer_selector_add_layer (GHID_LAYER_SELECTOR (layersel), i,
848 text, color_string, active, TRUE, TRUE);
853 /*! \brief callback for ghid_layer_selector_delete_layers */
854 gboolean
855 get_layer_delete (gint layer)
857 return layer >= max_copper_layer;
860 /*! \brief Synchronize layer selector widget with current PCB state
861 * \par Function Description
862 * Called when user toggles layer visibility or changes drawing layer,
863 * or when layer visibility is changed programatically.
865 void
866 ghid_layer_buttons_update (void)
868 gint layer;
870 if (ignore_layer_update)
871 return;
873 ghid_layer_selector_delete_layers
874 (GHID_LAYER_SELECTOR (ghidgui->layer_selector),
875 get_layer_delete);
876 make_layer_buttons (ghidgui->layer_selector);
877 make_virtual_layer_buttons (ghidgui->layer_selector);
878 ghid_main_menu_install_layer_selector
879 (GHID_MAIN_MENU (ghidgui->menu_bar),
880 GHID_LAYER_SELECTOR (ghidgui->layer_selector));
882 /* Sync selected layer with PCB's state */
883 if (PCB->RatDraw)
884 layer = LAYER_BUTTON_RATS;
885 else if (PCB->SilkActive)
886 layer = LAYER_BUTTON_SILK;
887 else
888 layer = LayerStack[0];
890 ghid_layer_selector_select_layer
891 (GHID_LAYER_SELECTOR (ghidgui->layer_selector), layer);
894 /*! \brief Called when user clicks OK on route style dialog */
895 static void
896 route_styles_edited_cb (GHidRouteStyleSelector *rss, gboolean save,
897 gpointer data)
899 if (save)
901 g_free (Settings.Routes);
902 Settings.Routes = make_route_string (PCB->RouteStyle, NUM_STYLES);
903 ghidgui->config_modified = TRUE;
904 ghid_config_files_write ();
906 ghid_main_menu_install_route_style_selector
907 (GHID_MAIN_MENU (ghidgui->menu_bar),
908 GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
911 /*! \brief Called when a route style is selected */
912 static void
913 route_style_changed_cb (GHidRouteStyleSelector *rss, RouteStyleType *rst,
914 gpointer data)
916 pcb_use_route_style (rst);
917 ghid_set_status_line_label();
920 /*! \brief Configure the route style selector */
921 void
922 make_route_style_buttons (GHidRouteStyleSelector *rss)
924 int i;
925 for (i = 0; i < NUM_STYLES; ++i)
926 ghid_route_style_selector_add_route_style (rss, &PCB->RouteStyle[i]);
927 g_signal_connect (G_OBJECT (rss), "select_style",
928 G_CALLBACK (route_style_changed_cb), NULL);
929 g_signal_connect (G_OBJECT (rss), "style_edited",
930 G_CALLBACK (route_styles_edited_cb), NULL);
931 ghid_main_menu_install_route_style_selector
932 (GHID_MAIN_MENU (ghidgui->menu_bar),
933 GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
937 * ---------------------------------------------------------------
938 * Mode buttons
940 typedef struct
942 GtkWidget *button;
943 GtkWidget *toolbar_button;
944 guint button_cb_id;
945 guint toolbar_button_cb_id;
946 gchar *name;
947 gint mode;
948 gchar **xpm;
950 ModeButton;
953 static ModeButton mode_buttons[] = {
954 {NULL, NULL, 0, 0, "via", VIA_MODE, via},
955 {NULL, NULL, 0, 0, "line", LINE_MODE, line},
956 {NULL, NULL, 0, 0, "arc", ARC_MODE, arc},
957 {NULL, NULL, 0, 0, "text", TEXT_MODE, text},
958 {NULL, NULL, 0, 0, "rectangle", RECTANGLE_MODE, rect},
959 {NULL, NULL, 0, 0, "polygon", POLYGON_MODE, poly},
960 {NULL, NULL, 0, 0, "polygonhole", POLYGONHOLE_MODE, polyhole},
961 {NULL, NULL, 0, 0, "buffer", PASTEBUFFER_MODE, buf},
962 {NULL, NULL, 0, 0, "remove", REMOVE_MODE, del},
963 {NULL, NULL, 0, 0, "rotate", ROTATE_MODE, rot},
964 {NULL, NULL, 0, 0, "insertPoint", INSERTPOINT_MODE, ins},
965 {NULL, NULL, 0, 0, "thermal", THERMAL_MODE, thrm},
966 {NULL, NULL, 0, 0, "select", ARROW_MODE, sel},
967 {NULL, NULL, 0, 0, "lock", LOCK_MODE, lock}
970 static gint n_mode_buttons = G_N_ELEMENTS (mode_buttons);
972 static void
973 do_set_mode (int mode)
975 SetMode (mode);
976 ghid_mode_cursor (mode);
977 ghidgui->settings_mode = mode;
980 static void
981 mode_toolbar_button_toggled_cb (GtkToggleButton *button, ModeButton * mb)
983 gboolean active = gtk_toggle_button_get_active (button);
985 if (mb->button != NULL)
987 g_signal_handler_block (mb->button, mb->button_cb_id);
988 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->button), active);
989 g_signal_handler_unblock (mb->button, mb->button_cb_id);
992 if (active)
993 do_set_mode (mb->mode);
996 static void
997 mode_button_toggled_cb (GtkWidget * widget, ModeButton * mb)
999 gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
1001 if (mb->toolbar_button != NULL)
1003 g_signal_handler_block (mb->toolbar_button, mb->toolbar_button_cb_id);
1004 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->toolbar_button), active);
1005 g_signal_handler_unblock (mb->toolbar_button, mb->toolbar_button_cb_id);
1008 if (active)
1009 do_set_mode (mb->mode);
1012 void
1013 ghid_mode_buttons_update (void)
1015 ModeButton *mb;
1016 gint i;
1018 for (i = 0; i < n_mode_buttons; ++i)
1020 mb = &mode_buttons[i];
1021 if (Settings.Mode == mb->mode)
1023 g_signal_handler_block (mb->button, mb->button_cb_id);
1024 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->button), TRUE);
1025 g_signal_handler_unblock (mb->button, mb->button_cb_id);
1027 g_signal_handler_block (mb->toolbar_button, mb->toolbar_button_cb_id);
1028 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->toolbar_button), TRUE);
1029 g_signal_handler_unblock (mb->toolbar_button, mb->toolbar_button_cb_id);
1030 break;
1035 void
1036 ghid_pack_mode_buttons (void)
1038 if (ghidgui->compact_vertical)
1040 gtk_widget_hide (ghidgui->mode_buttons_frame);
1041 gtk_widget_show_all (ghidgui->mode_toolbar);
1043 else
1045 gtk_widget_hide (ghidgui->mode_toolbar);
1046 gtk_widget_show_all (ghidgui->mode_buttons_frame);
1050 static void
1051 make_mode_buttons_and_toolbar (GtkWidget **mode_frame,
1052 GtkWidget **mode_toolbar)
1054 GtkToolItem *tool_item;
1055 GtkWidget *vbox, *hbox = NULL;
1056 GtkWidget *image;
1057 GdkPixbuf *pixbuf;
1058 GSList *group = NULL;
1059 GSList *toolbar_group = NULL;
1060 ModeButton *mb;
1061 int i;
1063 *mode_toolbar = gtk_toolbar_new ();
1065 *mode_frame = gtk_frame_new (NULL);
1066 vbox = gtk_vbox_new (FALSE, 0);
1067 gtk_container_add (GTK_CONTAINER (*mode_frame), vbox);
1069 for (i = 0; i < n_mode_buttons; ++i)
1071 mb = &mode_buttons[i];
1073 /* Create tool button for mode frame */
1074 mb->button = gtk_radio_button_new (group);
1075 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (mb->button));
1076 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (mb->button), FALSE);
1078 /* Create tool button for toolbar */
1079 mb->toolbar_button = gtk_radio_button_new (toolbar_group);
1080 toolbar_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (mb->toolbar_button));
1081 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (mb->toolbar_button), FALSE);
1083 /* Pack mode-frame button into the frame */
1084 if ((i % ghidgui->n_mode_button_columns) == 0)
1086 hbox = gtk_hbox_new (FALSE, 0);
1087 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1089 gtk_box_pack_start (GTK_BOX (hbox), mb->button, FALSE, FALSE, 0);
1091 /* Create a container for the toolbar button and add that */
1092 tool_item = gtk_tool_item_new ();
1093 gtk_container_add (GTK_CONTAINER (tool_item), mb->toolbar_button);
1094 gtk_toolbar_insert (GTK_TOOLBAR (*mode_toolbar), tool_item, -1);
1096 /* Load the image for the button, create GtkImage widgets for both
1097 * the grid button and the toolbar button, then pack into the buttons
1099 pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **) mb->xpm);
1100 image = gtk_image_new_from_pixbuf (pixbuf);
1101 gtk_container_add (GTK_CONTAINER (mb->button), image);
1102 image = gtk_image_new_from_pixbuf (pixbuf);
1103 gtk_container_add (GTK_CONTAINER (mb->toolbar_button), image);
1104 g_object_unref (pixbuf);
1106 if (strcmp (mb->name, "select") == 0)
1108 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->button), TRUE);
1109 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->toolbar_button), TRUE);
1112 mb->button_cb_id =
1113 g_signal_connect (mb->button, "toggled",
1114 G_CALLBACK (mode_button_toggled_cb), mb);
1115 mb->toolbar_button_cb_id =
1116 g_signal_connect (mb->toolbar_button, "toggled",
1117 G_CALLBACK (mode_toolbar_button_toggled_cb), mb);
1123 * ---------------------------------------------------------------
1124 * Top window
1125 * ---------------------------------------------------------------
1128 static gint
1129 delete_chart_cb (GtkWidget * widget, GdkEvent * event, GHidPort * port)
1131 ghid_config_files_write ();
1132 hid_action ("Quit");
1135 * Return TRUE to keep our app running. A FALSE here would let the
1136 * delete signal continue on and kill our program.
1138 return TRUE;
1141 static void
1142 destroy_chart_cb (GtkWidget * widget, GHidPort * port)
1144 ghid_shutdown_renderer (port);
1145 gtk_main_quit ();
1148 static void
1149 get_widget_styles (GtkStyle **menu_bar_style,
1150 GtkStyle **tool_button_style,
1151 GtkStyle **tool_button_label_style)
1153 GtkWidget *tool_button;
1154 GtkWidget *tool_button_label;
1155 GtkToolItem *tool_item;
1157 /* Build a tool item to extract the theme's styling for a toolbar button with text */
1158 tool_item = gtk_tool_item_new ();
1159 gtk_toolbar_insert (GTK_TOOLBAR (ghidgui->mode_toolbar), tool_item, 0);
1160 tool_button = gtk_button_new ();
1161 gtk_container_add (GTK_CONTAINER (tool_item), tool_button);
1162 tool_button_label = gtk_label_new ("");
1163 gtk_container_add (GTK_CONTAINER (tool_button), tool_button_label);
1165 /* Grab the various styles we need */
1166 gtk_widget_ensure_style (ghidgui->menu_bar);
1167 *menu_bar_style = gtk_widget_get_style (ghidgui->menu_bar);
1169 gtk_widget_ensure_style (tool_button);
1170 *tool_button_style = gtk_widget_get_style (tool_button);
1172 gtk_widget_ensure_style (tool_button_label);
1173 *tool_button_label_style = gtk_widget_get_style (tool_button_label);
1175 gtk_widget_destroy (GTK_WIDGET (tool_item));
1178 static void
1179 do_fix_topbar_theming (void)
1181 GtkWidget *rel_pos_frame;
1182 GtkWidget *abs_pos_frame;
1183 GtkStyle *menu_bar_style;
1184 GtkStyle *tool_button_style;
1185 GtkStyle *tool_button_label_style;
1187 get_widget_styles (&menu_bar_style,
1188 &tool_button_style,
1189 &tool_button_label_style);
1191 /* Style the top bar background as if it were all a menu bar */
1192 gtk_widget_set_style (ghidgui->top_bar_background, menu_bar_style);
1194 /* Style the cursor position labels using the menu bar style as well.
1195 * If this turns out to cause problems with certain gtk themes, we may
1196 * need to grab the GtkStyle associated with an actual menu item to
1197 * get a text color to render with.
1199 gtk_widget_set_style (ghidgui->cursor_position_relative_label, menu_bar_style);
1200 gtk_widget_set_style (ghidgui->cursor_position_absolute_label, menu_bar_style);
1202 /* Style the units button as if it were a toolbar button - hopefully
1203 * this isn't too ugly sitting on a background themed as a menu bar.
1204 * It is unlikely any theme defines colours for a GtkButton sitting on
1205 * a menu bar.
1207 rel_pos_frame = gtk_widget_get_parent (ghidgui->cursor_position_relative_label);
1208 abs_pos_frame = gtk_widget_get_parent (ghidgui->cursor_position_absolute_label);
1209 gtk_widget_set_style (rel_pos_frame, menu_bar_style);
1210 gtk_widget_set_style (abs_pos_frame, menu_bar_style);
1211 gtk_widget_set_style (ghidgui->grid_units_button, tool_button_style);
1212 gtk_widget_set_style (ghidgui->grid_units_label, tool_button_label_style);
1215 /* Attempt to produce a conststent style for our extra menu-bar items by
1216 * copying aspects from the menu bar style set by the user's GTK theme.
1217 * Setup signal handlers to update our efforts if the user changes their
1218 * theme whilst we are running.
1220 static void
1221 fix_topbar_theming (void)
1223 GtkSettings *settings;
1225 do_fix_topbar_theming ();
1227 settings = gtk_widget_get_settings (ghidgui->top_bar_background);
1228 g_signal_connect (settings, "notify::gtk-theme-name",
1229 G_CALLBACK (do_fix_topbar_theming), NULL);
1230 g_signal_connect (settings, "notify::gtk-font-name",
1231 G_CALLBACK (do_fix_topbar_theming), NULL);
1235 * Create the top_window contents. The config settings should be loaded
1236 * before this is called.
1238 static void
1239 ghid_build_pcb_top_window (void)
1241 GtkWidget *window;
1242 GtkWidget *vbox_main, *hbox_middle, *hbox;
1243 GtkWidget *vbox, *frame;
1244 GtkWidget *label;
1245 /* FIXME: IFDEF HACK */
1246 #ifdef ENABLE_GL
1247 GtkWidget *trackball;
1248 #endif
1249 GHidPort *port = &ghid_port;
1250 GtkWidget *scrolled;
1252 window = gport->top_window;
1254 vbox_main = gtk_vbox_new (FALSE, 0);
1255 gtk_container_add (GTK_CONTAINER (window), vbox_main);
1257 /* -- Top control bar */
1258 ghidgui->top_bar_background = gtk_event_box_new ();
1259 gtk_box_pack_start (GTK_BOX (vbox_main),
1260 ghidgui->top_bar_background, FALSE, FALSE, 0);
1262 ghidgui->top_hbox = gtk_hbox_new (FALSE, 4);
1263 gtk_container_add (GTK_CONTAINER (ghidgui->top_bar_background),
1264 ghidgui->top_hbox);
1267 * menu_hbox will be made insensitive when the gui needs
1268 * a modal button GetLocation button press.
1270 ghidgui->menu_hbox = gtk_hbox_new (FALSE, 0);
1271 gtk_box_pack_start (GTK_BOX (ghidgui->top_hbox), ghidgui->menu_hbox,
1272 FALSE, FALSE, 0);
1274 ghidgui->menubar_toolbar_vbox = gtk_vbox_new (FALSE, 0);
1275 gtk_box_pack_start (GTK_BOX (ghidgui->menu_hbox),
1276 ghidgui->menubar_toolbar_vbox, FALSE, FALSE, 0);
1278 /* Build layer menus */
1279 ghidgui->layer_selector = ghid_layer_selector_new ();
1280 make_layer_buttons (ghidgui->layer_selector);
1281 make_virtual_layer_buttons (ghidgui->layer_selector);
1282 g_signal_connect (G_OBJECT (ghidgui->layer_selector), "select-layer",
1283 G_CALLBACK (layer_selector_select_callback),
1284 NULL);
1285 g_signal_connect (G_OBJECT (ghidgui->layer_selector), "toggle-layer",
1286 G_CALLBACK (layer_selector_toggle_callback),
1287 NULL);
1288 g_signal_connect (G_OBJECT (ghidgui->layer_selector), "rename-layer",
1289 G_CALLBACK (layer_selector_rename_callback),
1290 NULL);
1291 /* Build main menu */
1292 ghidgui->menu_bar = ghid_load_menus ();
1293 gtk_box_pack_start (GTK_BOX (ghidgui->menubar_toolbar_vbox),
1294 ghidgui->menu_bar, FALSE, FALSE, 0);
1296 make_mode_buttons_and_toolbar (&ghidgui->mode_buttons_frame,
1297 &ghidgui->mode_toolbar);
1298 gtk_box_pack_start (GTK_BOX (ghidgui->menubar_toolbar_vbox),
1299 ghidgui->mode_toolbar, FALSE, FALSE, 0);
1302 ghidgui->position_hbox = gtk_hbox_new (FALSE, 0);
1303 gtk_box_pack_end (GTK_BOX(ghidgui->top_hbox),
1304 ghidgui->position_hbox, FALSE, FALSE, 4);
1306 make_cursor_position_labels (ghidgui->position_hbox, port);
1308 hbox_middle = gtk_hbox_new (FALSE, 0);
1309 gtk_box_pack_start (GTK_BOX (vbox_main), hbox_middle, TRUE, TRUE, 3);
1311 fix_topbar_theming (); /* Must be called after toolbar is created */
1313 /* -- Left control bar */
1315 * This box will be made insensitive when the gui needs
1316 * a modal button GetLocation button press.
1318 ghidgui->left_toolbar = gtk_vbox_new (FALSE, 0);
1319 gtk_box_pack_start (GTK_BOX (hbox_middle),
1320 ghidgui->left_toolbar, FALSE, FALSE, 3);
1322 vbox = ghid_scrolled_vbox (ghidgui->left_toolbar, &scrolled,
1323 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1324 gtk_box_pack_start (GTK_BOX(vbox), ghidgui->layer_selector,
1325 FALSE, FALSE, 0);
1327 /* FIXME: IFDEF HACK */
1328 #ifdef ENABLE_GL
1329 trackball = ghid_trackball_new ();
1330 g_signal_connect (trackball, "rotation-changed",
1331 G_CALLBACK (ghid_port_rotate), NULL);
1332 g_signal_connect (trackball, "view-2d-changed",
1333 G_CALLBACK (ghid_view_2d), NULL);
1334 gtk_box_pack_start (GTK_BOX(ghidgui->left_toolbar),
1335 trackball, FALSE, FALSE, 0);
1336 #endif
1338 /* ghidgui->mode_buttons_frame was created above in the call to
1339 * make_mode_buttons_and_toolbar (...);
1341 gtk_box_pack_start (GTK_BOX (ghidgui->left_toolbar),
1342 ghidgui->mode_buttons_frame, FALSE, FALSE, 0);
1344 frame = gtk_frame_new(NULL);
1345 gtk_box_pack_end (GTK_BOX (ghidgui->left_toolbar), frame, FALSE, FALSE, 0);
1346 vbox = gtk_vbox_new(FALSE, 0);
1347 gtk_container_add(GTK_CONTAINER(frame), vbox);
1348 hbox = gtk_hbox_new(FALSE, 0);
1349 gtk_box_pack_start(GTK_BOX (vbox), hbox, FALSE, FALSE, 1);
1350 ghidgui->route_style_selector = ghid_route_style_selector_new ();
1351 make_route_style_buttons
1352 (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
1353 gtk_box_pack_start(GTK_BOX(hbox), ghidgui->route_style_selector,
1354 FALSE, FALSE, 4);
1356 ghidgui->vbox_middle = gtk_vbox_new (FALSE, 0);
1357 gtk_box_pack_start (GTK_BOX (hbox_middle),
1358 ghidgui->vbox_middle, TRUE, TRUE, 0);
1360 hbox = gtk_hbox_new (FALSE, 0);
1361 gtk_box_pack_start (GTK_BOX (ghidgui->vbox_middle), hbox, TRUE, TRUE, 0);
1363 /* -- The PCB layout output drawing area */
1365 gport->drawing_area = gtk_drawing_area_new ();
1366 ghid_init_drawing_widget (gport->drawing_area, gport);
1368 gtk_widget_add_events (gport->drawing_area, GDK_EXPOSURE_MASK
1369 | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
1370 | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK
1371 | GDK_KEY_RELEASE_MASK | GDK_KEY_PRESS_MASK
1372 | GDK_FOCUS_CHANGE_MASK | GDK_POINTER_MOTION_MASK
1373 | GDK_POINTER_MOTION_HINT_MASK);
1376 * This is required to get the drawing_area key-press-event. Also the
1377 * enter and button press callbacks grab focus to be sure we have it
1378 * when in the drawing_area.
1380 gtk_widget_set_can_focus (gport->drawing_area, TRUE);
1382 gtk_box_pack_start (GTK_BOX (hbox), gport->drawing_area, TRUE, TRUE, 0);
1384 ghidgui->v_adjustment = gtk_adjustment_new (0.0, 0.0, 100.0,
1385 10.0, 10.0, 10.0);
1386 ghidgui->v_range =
1387 gtk_vscrollbar_new (GTK_ADJUSTMENT (ghidgui->v_adjustment));
1389 gtk_box_pack_start (GTK_BOX (hbox), ghidgui->v_range, FALSE, FALSE, 0);
1391 g_signal_connect (G_OBJECT (ghidgui->v_adjustment), "value_changed",
1392 G_CALLBACK (v_adjustment_changed_cb), ghidgui);
1394 ghidgui->h_adjustment = gtk_adjustment_new (0.0, 0.0, 100.0,
1395 10.0, 10.0, 10.0);
1396 ghidgui->h_range =
1397 gtk_hscrollbar_new (GTK_ADJUSTMENT (ghidgui->h_adjustment));
1398 gtk_box_pack_start (GTK_BOX (ghidgui->vbox_middle),
1399 ghidgui->h_range, FALSE, FALSE, 0);
1401 g_signal_connect (G_OBJECT (ghidgui->h_adjustment), "value_changed",
1402 G_CALLBACK (h_adjustment_changed_cb), ghidgui);
1404 /* -- The bottom status line label */
1405 ghidgui->status_line_hbox = gtk_hbox_new (FALSE, 0);
1406 gtk_box_pack_start (GTK_BOX (ghidgui->vbox_middle),
1407 ghidgui->status_line_hbox, FALSE, FALSE, 2);
1409 label = gtk_label_new ("");
1410 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
1411 gtk_box_pack_start (GTK_BOX (ghidgui->status_line_hbox), label, FALSE,
1412 FALSE, 0);
1413 ghidgui->status_line_label = label;
1415 /* Depending on user setting, the command_combo_box may get packed into
1416 | the status_line_hbox, but it will happen on demand the first time
1417 | the user does a command entry.
1420 g_signal_connect (G_OBJECT (gport->drawing_area), "realize",
1421 G_CALLBACK (ghid_port_drawing_realize_cb),
1422 port);
1423 g_signal_connect (G_OBJECT (gport->drawing_area), "expose_event",
1424 G_CALLBACK (ghid_drawing_area_expose_cb),
1425 port);
1426 g_signal_connect (G_OBJECT (gport->top_window), "configure_event",
1427 G_CALLBACK (top_window_configure_event_cb), port);
1428 g_signal_connect (gport->top_window, "enter-notify-event",
1429 G_CALLBACK (top_window_enter_cb), port);
1430 g_signal_connect (G_OBJECT (gport->drawing_area), "configure_event",
1431 G_CALLBACK (ghid_port_drawing_area_configure_event_cb),
1432 port);
1435 /* Mouse and key events will need to be intercepted when PCB needs a
1436 | location from the user.
1439 ghid_interface_input_signals_connect ();
1441 g_signal_connect (G_OBJECT (gport->drawing_area), "enter_notify_event",
1442 G_CALLBACK (ghid_port_window_enter_cb), port);
1443 g_signal_connect (G_OBJECT (gport->drawing_area), "leave_notify_event",
1444 G_CALLBACK (ghid_port_window_leave_cb), port);
1445 g_signal_connect (G_OBJECT (gport->drawing_area), "motion_notify_event",
1446 G_CALLBACK (ghid_port_window_motion_cb), port);
1450 g_signal_connect (G_OBJECT (window), "delete_event",
1451 G_CALLBACK (delete_chart_cb), port);
1452 g_signal_connect (G_OBJECT (window), "destroy",
1453 G_CALLBACK (destroy_chart_cb), port);
1455 ghidgui->creating = FALSE;
1457 gtk_widget_show_all (gport->top_window);
1458 ghid_pack_mode_buttons ();
1459 gdk_window_set_back_pixmap (gtk_widget_get_window (gport->drawing_area),
1460 NULL, FALSE);
1464 /* Connect and disconnect just the signals a g_main_loop() will need.
1465 | Cursor and motion events still need to be handled by the top level
1466 | loop, so don't connect/reconnect these.
1467 | A g_main_loop will be running when PCB wants the user to select a
1468 | location or if command entry is needed in the status line hbox.
1469 | During these times normal button/key presses are intercepted, either
1470 | by new signal handlers or the command_combo_box entry.
1472 static gulong button_press_handler;
1473 static gulong button_release_handler;
1474 static gulong scroll_event_handler;
1475 static gulong key_press_handler;
1476 static gulong key_release_handler;
1478 void
1479 ghid_interface_input_signals_connect (void)
1481 button_press_handler =
1482 g_signal_connect (G_OBJECT (gport->drawing_area), "button_press_event",
1483 G_CALLBACK (ghid_port_button_press_cb), NULL);
1485 button_release_handler =
1486 g_signal_connect (G_OBJECT (gport->drawing_area), "button_release_event",
1487 G_CALLBACK (ghid_port_button_release_cb), NULL);
1489 scroll_event_handler =
1490 g_signal_connect (G_OBJECT (gport->drawing_area), "scroll_event",
1491 G_CALLBACK (ghid_port_window_mouse_scroll_cb), NULL);
1493 key_press_handler =
1494 g_signal_connect (G_OBJECT (gport->drawing_area), "key_press_event",
1495 G_CALLBACK (ghid_port_key_press_cb), NULL);
1497 key_release_handler =
1498 g_signal_connect (G_OBJECT (gport->drawing_area), "key_release_event",
1499 G_CALLBACK (ghid_port_key_release_cb), NULL);
1502 void
1503 ghid_interface_input_signals_disconnect (void)
1505 if (button_press_handler)
1506 g_signal_handler_disconnect (gport->drawing_area, button_press_handler);
1508 if (button_release_handler)
1509 g_signal_handler_disconnect (gport->drawing_area, button_release_handler);
1511 if (scroll_event_handler)
1512 g_signal_handler_disconnect (gport->drawing_area, scroll_event_handler);
1514 if (key_press_handler)
1515 g_signal_handler_disconnect (gport->drawing_area, key_press_handler);
1517 if (key_release_handler)
1518 g_signal_handler_disconnect (gport->drawing_area, key_release_handler);
1520 button_press_handler = 0;
1521 button_release_handler = 0;
1522 scroll_event_handler = 0;
1523 key_press_handler = 0;
1524 key_release_handler = 0;
1528 /* We'll set the interface insensitive when a g_main_loop is running so the
1529 | Gtk menus and buttons don't respond and interfere with the special entry
1530 | the user needs to be doing.
1532 void
1533 ghid_interface_set_sensitive (gboolean sensitive)
1535 gtk_widget_set_sensitive (ghidgui->left_toolbar, sensitive);
1536 gtk_widget_set_sensitive (ghidgui->menu_hbox, sensitive);
1540 /* ----------------------------------------------------------------------
1541 * initializes icon pixmap and also cursor bit maps
1543 static void
1544 ghid_init_icons (GHidPort * port)
1546 GdkWindow *window = gtk_widget_get_window (gport->top_window);
1548 XC_clock_source = gdk_bitmap_create_from_data (window,
1549 (char *) rotateIcon_bits,
1550 rotateIcon_width,
1551 rotateIcon_height);
1552 XC_clock_mask =
1553 gdk_bitmap_create_from_data (window, (char *) rotateMask_bits,
1554 rotateMask_width, rotateMask_height);
1556 XC_hand_source = gdk_bitmap_create_from_data (window,
1557 (char *) handIcon_bits,
1558 handIcon_width,
1559 handIcon_height);
1560 XC_hand_mask =
1561 gdk_bitmap_create_from_data (window, (char *) handMask_bits,
1562 handMask_width, handMask_height);
1564 XC_lock_source = gdk_bitmap_create_from_data (window,
1565 (char *) lockIcon_bits,
1566 lockIcon_width,
1567 lockIcon_height);
1568 XC_lock_mask =
1569 gdk_bitmap_create_from_data (window, (char *) lockMask_bits,
1570 lockMask_width, lockMask_height);
1573 void
1574 ghid_create_pcb_widgets (void)
1576 GHidPort *port = &ghid_port;
1577 GError *err = NULL;
1579 if (bg_image_file)
1580 ghidgui->bg_pixbuf = gdk_pixbuf_new_from_file(bg_image_file, &err);
1581 if (err)
1583 g_error("%s", err->message);
1584 g_error_free(err);
1586 ghid_build_pcb_top_window ();
1587 ghid_install_accel_groups (GTK_WINDOW (port->top_window), ghidgui);
1588 ghid_update_toggle_flags ();
1590 ghid_init_icons (port);
1591 SetMode (ARROW_MODE);
1592 ghid_mode_buttons_update ();
1595 static gboolean
1596 ghid_listener_cb (GIOChannel *source,
1597 GIOCondition condition,
1598 gpointer data)
1600 GIOStatus status;
1601 gchar *str;
1602 gsize len;
1603 gsize term;
1604 GError *err = NULL;
1607 if (condition & G_IO_HUP)
1609 gui->log (_("Read end of pipe died!\n"));
1610 return FALSE;
1613 if (condition == G_IO_IN)
1615 status = g_io_channel_read_line (source, &str, &len, &term, &err);
1616 switch (status)
1618 case G_IO_STATUS_NORMAL:
1619 hid_parse_actions (str);
1620 g_free (str);
1621 break;
1623 case G_IO_STATUS_ERROR:
1624 gui->log (_("ERROR status from g_io_channel_read_line\n"));
1625 return FALSE;
1626 break;
1628 case G_IO_STATUS_EOF:
1629 gui->log (_("Input pipe returned EOF. The --listen option is \n"
1630 "probably not running anymore in this session.\n"));
1631 return FALSE;
1632 break;
1634 case G_IO_STATUS_AGAIN:
1635 gui->log (_("AGAIN status from g_io_channel_read_line\n"));
1636 return FALSE;
1637 break;
1639 default:
1640 fprintf (stderr, _("ERROR: unhandled case in ghid_listener_cb\n"));
1641 return FALSE;
1642 break;
1646 else
1647 fprintf (stderr, _("Unknown condition in ghid_listener_cb\n"));
1649 return TRUE;
1652 static void
1653 ghid_create_listener (void)
1655 GIOChannel *channel;
1656 int fd = fileno (stdin);
1658 channel = g_io_channel_unix_new (fd);
1659 g_io_add_watch (channel, G_IO_IN, ghid_listener_cb, NULL);
1663 /* ------------------------------------------------------------ */
1665 static int stdin_listen = 0;
1666 static char *pcbmenu_path = "gpcb-menu.res";
1668 HID_Attribute ghid_attribute_list[] = {
1670 /* %start-doc options "21 GTK+ GUI Options"
1671 @ftable @code
1672 @item --listen
1673 Listen for actions on stdin.
1674 @end ftable
1675 %end-doc
1677 {"listen", "Listen for actions on stdin",
1678 HID_Boolean, 0, 0, {0, 0, 0}, 0, &stdin_listen},
1679 #define HA_listen 0
1681 /* %start-doc options "21 GTK+ GUI Options"
1682 @ftable @code
1683 @item --bg-image <string>
1684 File name of an image to put into the background of the GUI canvas. The image must
1685 be a color PPM image, in binary (not ASCII) format. It can be any size, and will be
1686 automatically scaled to fit the canvas.
1687 @end ftable
1688 %end-doc
1690 {"bg-image", "Background Image",
1691 HID_String, 0, 0, {0, 0, 0}, 0, &bg_image_file},
1692 #define HA_bg_image 1
1694 /* %start-doc options "21 GTK+ GUI Options"
1695 @ftable @code
1696 @item --pcb-menu <string>
1697 Location of the @file{gpcb-menu.res} file which defines the menu for the GTK+ GUI.
1698 @end ftable
1699 %end-doc
1701 {"pcb-menu", "Location of gpcb-menu.res file",
1702 HID_String, 0, 0, {0, PCBLIBDIR "/gpcb-menu.res", 0}, 0, &pcbmenu_path}
1703 #define HA_pcbmenu 2
1706 REGISTER_ATTRIBUTES (ghid_attribute_list)
1708 HID_Attribute *
1709 ghid_get_export_options (int *n_ret)
1711 *n_ret = sizeof (ghid_attribute_list) / sizeof (HID_Attribute);
1712 return ghid_attribute_list;
1715 /* Create top level window for routines that will need top_window
1716 | before ghid_create_pcb_widgets() is called.
1718 void
1719 ghid_parse_arguments (int *argc, char ***argv)
1721 GtkWidget *window;
1722 gint i;
1723 GdkPixbuf *icon;
1725 /* on windows we need to figure out the installation directory */
1726 #ifdef WIN32
1727 char * tmps;
1728 char * libdir;
1729 tmps = g_win32_get_package_installation_directory(PACKAGE "-" VERSION, NULL);
1730 #define REST_OF_PATH G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S PACKAGE G_DIR_SEPARATOR_S "newlib"
1731 libdir = (char *) malloc(strlen(tmps) +
1732 strlen(REST_OF_PATH) +
1734 sprintf(libdir, "%s%s", tmps, REST_OF_PATH);
1735 free(tmps);
1737 Settings.LibraryTree = libdir;
1739 #undef REST_OF_PATH
1741 #endif
1743 #if defined (DEBUG)
1744 for (i = 0; i < *argc; i++)
1746 printf ("ghid_parse_arguments(): *argv[%d] = \"%s\"\n", i, (*argv)[i]);
1748 #endif
1750 /* Threads aren't used in PCB, but this call would go here.
1752 /* g_thread_init (NULL); */
1754 #if defined (ENABLE_NLS)
1755 /* Do our own setlocale() stufff since we want to override LC_NUMERIC
1757 gtk_set_locale ();
1758 setlocale (LC_NUMERIC, "C"); /* use decimal point instead of comma */
1759 #endif
1762 * Prevent gtk_init() and gtk_init_check() from automatically
1763 * calling setlocale (LC_ALL, "") which would undo LC_NUMERIC if ENABLE_NLS
1764 * We also don't want locale set if no ENABLE_NLS to keep "C" LC_NUMERIC.
1766 gtk_disable_setlocale ();
1768 gtk_init (argc, argv);
1770 gport = &ghid_port;
1771 gport->view.coord_per_px = 300.0;
1772 pixel_slop = 300;
1774 ghid_init_renderer (argc, argv, gport);
1776 ghid_config_files_read (argc, argv);
1778 Settings.AutoPlace = 0;
1779 for (i = 0; i < *argc; i++)
1781 if (strcmp ((*argv)[i], "-auto-place") == 0)
1782 Settings.AutoPlace = 1;
1785 #ifdef ENABLE_NLS
1786 #ifdef LOCALEDIR
1787 bindtextdomain (PACKAGE, LOCALEDIR);
1788 #endif
1789 textdomain (PACKAGE);
1790 bind_textdomain_codeset (PACKAGE, "UTF-8");
1791 #endif /* ENABLE_NLS */
1793 icon = gdk_pixbuf_new_from_xpm_data ((const gchar **) icon_bits);
1794 gtk_window_set_default_icon (icon);
1796 window = gport->top_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1797 gtk_window_set_title (GTK_WINDOW (window), "PCB");
1798 gtk_window_set_default_size(GTK_WINDOW(window),
1799 ghidgui->top_window_width, ghidgui->top_window_height);
1801 if (Settings.AutoPlace)
1802 gtk_window_move (GTK_WINDOW (window), 10, 10);
1804 gtk_widget_show_all (gport->top_window);
1805 ghidgui->creating = TRUE;
1808 void
1809 ghid_do_export (HID_Attr_Val * options)
1811 ghid_create_pcb_widgets ();
1813 /* These are needed to make sure the @layerpick and @layerview menus
1814 * are properly initialized and synchronized with the current PCB.
1816 ghid_layer_buttons_update ();
1817 ghid_main_menu_install_route_style_selector
1818 (GHID_MAIN_MENU (ghidgui->menu_bar),
1819 GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
1821 if (stdin_listen)
1822 ghid_create_listener ();
1824 ghid_notify_gui_is_up ();
1826 gtk_main ();
1827 ghid_config_files_write ();
1831 /*! \brief callback for */
1832 static gboolean
1833 get_layer_visible_cb (int id)
1835 int visible;
1836 layer_process (NULL, NULL, &visible, id);
1837 return visible;
1840 gint
1841 LayersChanged (int argc, char **argv, Coord x, Coord y)
1843 if (!ghidgui || !ghidgui->menu_bar)
1844 return 0;
1846 ghid_config_groups_changed();
1847 ghid_layer_buttons_update ();
1848 ghid_layer_selector_show_layers
1849 (GHID_LAYER_SELECTOR (ghidgui->layer_selector), get_layer_visible_cb);
1851 /* FIXME - if a layer is moved it should retain its color. But layers
1852 | currently can't do that because color info is not saved in the
1853 | pcb file. So this makes a moved layer change its color to reflect
1854 | the way it will be when the pcb is reloaded.
1856 pcb_colors_from_settings (PCB);
1857 return 0;
1860 static const char toggleview_syntax[] =
1861 "ToggleView(1..MAXLAYER)\n"
1862 "ToggleView(layername)\n"
1863 "ToggleView(Silk|Rats|Pins|Vias|Mask|BackSide)";
1865 static const char toggleview_help[] =
1866 "Toggle the visibility of the specified layer or layer group.";
1868 /* %start-doc actions ToggleView
1870 If you pass an integer, that layer is specified by index (the first
1871 layer is @code{1}, etc). If you pass a layer name, that layer is
1872 specified by name. When a layer is specified, the visibility of the
1873 layer group containing that layer is toggled.
1875 If you pass a special layer name, the visibility of those components
1876 (silk, rats, etc) is toggled. Note that if you have a layer named
1877 the same as a special layer, the layer is chosen over the special layer.
1879 %end-doc */
1881 static int
1882 ToggleView (int argc, char **argv, Coord x, Coord y)
1884 int i, l;
1886 #ifdef DEBUG_MENUS
1887 puts ("Starting ToggleView().");
1888 #endif
1890 if (argc == 0)
1892 AFAIL (toggleview);
1894 if (isdigit ((int) argv[0][0]))
1896 l = atoi (argv[0]) - 1;
1898 else if (strcmp (argv[0], "Silk") == 0)
1899 l = LAYER_BUTTON_SILK;
1900 else if (strcmp (argv[0], "Rats") == 0)
1901 l = LAYER_BUTTON_RATS;
1902 else if (strcmp (argv[0], "Pins") == 0)
1903 l = LAYER_BUTTON_PINS;
1904 else if (strcmp (argv[0], "Vias") == 0)
1905 l = LAYER_BUTTON_VIAS;
1906 else if (strcmp (argv[0], "Mask") == 0)
1907 l = LAYER_BUTTON_MASK;
1908 else if (strcmp (argv[0], "BackSide") == 0)
1909 l = LAYER_BUTTON_FARSIDE;
1910 else
1912 l = -1;
1913 for (i = 0; i < max_copper_layer + 2; i++)
1914 if (strcmp (argv[0], PCB->Data->Layer[i].Name) == 0)
1916 l = i;
1917 break;
1919 if (l == -1)
1921 AFAIL (toggleview);
1926 /* Now that we've figured out which toggle button ought to control
1927 * this layer, simply hit the button and let the pre-existing code deal
1929 ghid_layer_selector_toggle_layer
1930 (GHID_LAYER_SELECTOR (ghidgui->layer_selector), l);
1931 return 0;
1934 static const char selectlayer_syntax[] =
1935 "SelectLayer(1..MAXLAYER|Silk|Rats)";
1937 static const char selectlayer_help[] =
1938 "Select which layer is the current layer.";
1940 /* %start-doc actions SelectLayer
1942 The specified layer becomes the currently active layer. It is made
1943 visible if it is not already visible
1945 %end-doc */
1947 static int
1948 SelectLayer (int argc, char **argv, Coord x, Coord y)
1950 int i;
1951 int newl = -1;
1952 if (argc == 0)
1953 AFAIL (selectlayer);
1955 for (i = 0; i < max_copper_layer; ++i)
1956 if (strcasecmp (argv[0], PCB->Data->Layer[i].Name) == 0)
1957 newl = i;
1959 if (strcasecmp (argv[0], "silk") == 0)
1960 newl = LAYER_BUTTON_SILK;
1961 else if (strcasecmp (argv[0], "rats") == 0)
1962 newl = LAYER_BUTTON_RATS;
1963 else if (newl == -1)
1964 newl = atoi (argv[0]) - 1;
1966 #ifdef DEBUG_MENUS
1967 printf ("SelectLayer(): newl = %d\n", newl);
1968 #endif
1970 /* Now that we've figured out which radio button ought to select
1971 * this layer, simply hit the button and let the pre-existing code deal
1973 ghid_layer_selector_select_layer
1974 (GHID_LAYER_SELECTOR (ghidgui->layer_selector), newl);
1976 return 0;
1980 HID_Action gtk_topwindow_action_list[] = {
1981 {"LayersChanged", 0, LayersChanged,
1982 layerschanged_help, layerschanged_syntax},
1983 {"SelectLayer", 0, SelectLayer,
1984 selectlayer_help, selectlayer_syntax},
1985 {"ToggleView", 0, ToggleView,
1986 toggleview_help, toggleview_syntax}
1989 REGISTER_ACTIONS (gtk_topwindow_action_list)
1992 * This function is used to check if a specified hotkey in the menu
1993 * resource file is "special". In this case "special" means that gtk
1994 * assigns a particular meaning to it and the normal menu setup will
1995 * never see these key presses. We capture those and feed them back
1996 * into the menu callbacks. This function is called as new
1997 * accelerators are added when the menus are being built
1999 static void
2000 ghid_check_special_key (const char *accel, GtkAction *action,
2001 const Resource *node)
2003 size_t len;
2004 unsigned int mods;
2005 unsigned int ind;
2007 if (action == NULL || accel == NULL || *accel == '\0')
2008 return ;
2010 #ifdef DEBUG_MENUS
2011 printf ("%s(\"%s\", \"%s\")\n", __FUNCTION__, accel, name);
2012 #endif
2014 mods = 0;
2015 if (strstr (accel, "<alt>") )
2017 mods |= GHID_KEY_ALT;
2019 if (strstr (accel, "<ctrl>") )
2021 mods |= GHID_KEY_CONTROL;
2023 if (strstr (accel, "<shift>") )
2025 mods |= GHID_KEY_SHIFT;
2029 len = strlen (accel);
2031 #define CHECK_KEY(a) ((len >= strlen (a)) && (strcmp (accel + len - strlen (a), (a)) == 0))
2033 ind = 0;
2034 if ( CHECK_KEY ("Tab") )
2036 ind = mods | GHID_KEY_TAB;
2038 else if ( CHECK_KEY ("Up") )
2040 ind = mods | GHID_KEY_UP;
2042 else if ( CHECK_KEY ("Down") )
2044 ind = mods | GHID_KEY_DOWN;
2046 else if ( CHECK_KEY ("Left") )
2048 ind = mods | GHID_KEY_LEFT;
2050 else if ( CHECK_KEY ("Right") )
2052 ind = mods | GHID_KEY_RIGHT;
2055 if (ind > 0)
2057 if (ind >= N_HOTKEY_ACTIONS)
2059 fprintf (stderr, _("ERROR: overflow of the ghid_hotkey_actions array. Index = %d\n"
2060 "Please report this.\n"), ind);
2061 exit (1);
2064 ghid_hotkey_actions[ind].action = action;
2065 ghid_hotkey_actions[ind].node = node;
2066 #ifdef DEBUG_MENUS
2067 printf ("Adding \"special\" hotkey to ghid_hotkey_actions[%u] :"
2068 " %s (%s)\n", ind, accel, name);
2069 #endif
2073 /*! \brief Finds the gpcb-menu.res file */
2074 char *
2075 get_menu_filename (void)
2077 char *rv = NULL;
2078 char *home_pcbmenu = NULL;
2080 /* homedir is set by the core */
2081 if (homedir)
2083 Message (_("Note: home directory is \"%s\"\n"), homedir);
2084 home_pcbmenu = Concat (homedir, PCB_DIR_SEPARATOR_S, ".pcb",
2085 PCB_DIR_SEPARATOR_S, "gpcb-menu.res", NULL);
2087 else
2088 Message (_("Warning: could not determine home directory\n"));
2090 if (access ("gpcb-menu.res", R_OK) == 0)
2091 rv = strdup ("gpcb-menu.res");
2092 else if (home_pcbmenu != NULL && (access (home_pcbmenu, R_OK) == 0) )
2093 rv = home_pcbmenu;
2094 else if (access (pcbmenu_path, R_OK) == 0)
2095 rv = strdup (pcbmenu_path);
2097 return rv;
2100 static GtkWidget *
2101 ghid_load_menus (void)
2103 char *filename;
2104 const Resource *r = 0, *bir;
2105 const Resource *mr;
2106 GtkWidget *menu_bar = NULL;
2107 int i;
2109 for (i = 0; i < N_HOTKEY_ACTIONS; i++)
2111 ghid_hotkey_actions[i].action = NULL;
2112 ghid_hotkey_actions[i].node = NULL;
2115 bir = resource_parse (0, gpcb_menu_default);
2116 if (!bir)
2118 fprintf (stderr, _("Error: internal menu resource didn't parse\n"));
2119 exit(1);
2122 filename = get_menu_filename ();
2123 if (filename)
2125 Message (_("Loading menus from %s\n"), filename);
2126 r = resource_parse (filename, 0);
2129 if (!r)
2131 Message (_("Using default menus\n"));
2132 r = bir;
2134 free (filename);
2136 mr = resource_subres (r, "MainMenu");
2137 if (!mr)
2138 mr = resource_subres (bir, "MainMenu");
2140 if (mr)
2142 menu_bar = ghid_main_menu_new (G_CALLBACK (ghid_menu_cb),
2143 ghid_check_special_key);
2144 ghid_main_menu_add_resource (GHID_MAIN_MENU (menu_bar), mr);
2147 mr = resource_subres (r, "PopupMenus");
2148 if (!mr)
2149 mr = resource_subres (bir, "PopupMenus");
2151 if (mr)
2153 int i;
2154 for (i = 0; i < mr->c; i++)
2155 if (resource_type (mr->v[i]) == 101)
2156 /* This is a named resource which defines a popup menu */
2157 ghid_main_menu_add_popup_resource (GHID_MAIN_MENU (menu_bar),
2158 mr->v[i].name, mr->v[i].subres);
2161 #ifdef DEBUG_MENUS
2162 puts ("Finished loading menus.");
2163 #endif
2165 mr = resource_subres (r, "Mouse");
2166 if (!mr)
2167 mr = resource_subres (bir, "Mouse");
2168 if (mr)
2169 load_mouse_resource (mr);
2171 return menu_bar;
2174 /* ------------------------------------------------------------ */
2176 static const char adjuststyle_syntax[] =
2177 "AdjustStyle()\n";
2179 static const char adjuststyle_help[] =
2180 "Open the window which allows editing of the route styles.";
2182 /* %start-doc actions AdjustStyle
2184 Opens the window which allows editing of the route styles.
2186 %end-doc */
2188 static int
2189 AdjustStyle(int argc, char **argv, Coord x, Coord y)
2191 if (argc > 1)
2192 AFAIL (adjuststyle);
2194 ghid_route_style_selector_edit_dialog
2195 (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
2196 return 0;
2199 /* ------------------------------------------------------------ */
2201 static const char editlayergroups_syntax[] =
2202 "EditLayerGroups()\n";
2204 static const char editlayergroups_help[] =
2205 "Open the preferences window which allows editing of the layer groups.";
2207 /* %start-doc actions EditLayerGroups
2209 Opens the preferences window which is where the layer groups
2210 are edited. This action is primarily provides to provide menu
2211 resource compatibility with the lesstif HID.
2213 %end-doc */
2215 static int
2216 EditLayerGroups(int argc, char **argv, Coord x, Coord y)
2219 if (argc != 0)
2220 AFAIL (editlayergroups);
2222 hid_actionl ("DoWindows", "Preferences", NULL);
2224 return 0;
2227 /* ------------------------------------------------------------ */
2229 HID_Action ghid_menu_action_list[] = {
2230 {"AdjustStyle", 0, AdjustStyle, adjuststyle_help, adjuststyle_syntax},
2231 {"EditLayerGroups", 0, EditLayerGroups, editlayergroups_help, editlayergroups_syntax}
2234 REGISTER_ACTIONS (ghid_menu_action_list)