Make SelectLayer() respond to layer name as well as index
[geda-pcb/whiteaudio.git] / src / hid / gtk / gui-top-window.c
blob786024ec7d5b0c75d230cf7174114a56cd1021b2
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"
125 #ifdef HAVE_LIBDMALLOC
126 #include <dmalloc.h>
127 #endif
129 static bool ignore_layer_update;
131 static GtkWidget *ghid_load_menus (void);
133 GhidGui _ghidgui, *ghidgui = NULL;
135 GHidPort ghid_port, *gport;
137 static gchar *bg_image_file;
139 static struct { GtkAction *action; const Resource *node; }
140 ghid_hotkey_actions[256];
141 #define N_HOTKEY_ACTIONS \
142 (sizeof (ghid_hotkey_actions) / sizeof (ghid_hotkey_actions[0]))
145 /*! \brief callback for ghid_main_menu_update_toggle_state () */
146 void
147 menu_toggle_update_cb (GtkAction *act, const char *tflag, const char *aflag)
149 if (tflag != NULL)
151 int v = hid_get_flag (tflag);
152 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (act), !!v);
154 if (aflag != NULL)
156 int v = hid_get_flag (aflag);
157 gtk_action_set_sensitive (act, !!v);
161 /*! \brief sync the menu checkboxes with actual pcb state */
162 void
163 ghid_update_toggle_flags ()
165 ghid_main_menu_update_toggle_state (GHID_MAIN_MENU (ghidgui->menu_bar),
166 menu_toggle_update_cb);
169 static void
170 h_adjustment_changed_cb (GtkAdjustment * adj, GhidGui * g)
172 if (g->adjustment_changed_holdoff)
173 return;
175 ghid_port_ranges_changed ();
178 static void
179 v_adjustment_changed_cb (GtkAdjustment * adj, GhidGui * g)
181 if (g->adjustment_changed_holdoff)
182 return;
184 ghid_port_ranges_changed ();
187 /* Save size of top window changes so PCB can restart at its size at exit.
189 static gint
190 top_window_configure_event_cb (GtkWidget * widget, GdkEventConfigure * ev,
191 GHidPort * port)
193 GtkAllocation allocation;
194 gboolean new_w, new_h;
196 gtk_widget_get_allocation (widget, &allocation);
198 new_w = (ghidgui->top_window_width != allocation.width);
199 new_h = (ghidgui->top_window_height != allocation.height);
201 ghidgui->top_window_width = allocation.width;
202 ghidgui->top_window_height = allocation.height;
204 if (new_w || new_h)
205 ghidgui->config_modified = TRUE;
207 return FALSE;
210 static void
211 info_bar_response_cb (GtkInfoBar *info_bar,
212 gint response_id,
213 GhidGui *_gui)
215 gtk_widget_destroy (_gui->info_bar);
216 _gui->info_bar = NULL;
218 if (response_id == GTK_RESPONSE_ACCEPT)
219 RevertPCB ();
222 static void
223 close_file_modified_externally_prompt (void)
225 if (ghidgui->info_bar != NULL)
226 gtk_widget_destroy (ghidgui->info_bar);
227 ghidgui->info_bar = NULL;
230 static void
231 show_file_modified_externally_prompt (void)
233 GtkWidget *button;
234 GtkWidget *button_image;
235 GtkWidget *icon;
236 GtkWidget *label;
237 GtkWidget *content_area;
238 char *file_path_utf8;
239 char *secondary_text;
240 char *markup;
242 close_file_modified_externally_prompt ();
244 ghidgui->info_bar = gtk_info_bar_new ();
246 button = gtk_info_bar_add_button (GTK_INFO_BAR (ghidgui->info_bar),
247 _("Reload"),
248 GTK_RESPONSE_ACCEPT);
249 button_image = gtk_image_new_from_stock (GTK_STOCK_REFRESH,
250 GTK_ICON_SIZE_BUTTON);
251 gtk_button_set_image (GTK_BUTTON (button), button_image);
253 gtk_info_bar_add_button (GTK_INFO_BAR (ghidgui->info_bar),
254 GTK_STOCK_CANCEL,
255 GTK_RESPONSE_CANCEL);
256 gtk_info_bar_set_message_type (GTK_INFO_BAR (ghidgui->info_bar),
257 GTK_MESSAGE_WARNING);
258 gtk_box_pack_start (GTK_BOX (ghidgui->vbox_middle),
259 ghidgui->info_bar, FALSE, FALSE, 0);
260 gtk_box_reorder_child (GTK_BOX (ghidgui->vbox_middle), ghidgui->info_bar, 0);
263 g_signal_connect (ghidgui->info_bar, "response",
264 G_CALLBACK (info_bar_response_cb), ghidgui);
266 file_path_utf8 = g_filename_to_utf8 (PCB->Filename, -1, NULL, NULL, NULL);
268 secondary_text = PCB->Changed ? "Do you want to drop your changes and reload the file?" :
269 "Do you want to reload the file?";
271 markup = g_markup_printf_escaped (_("<b>The file %s has changed on disk</b>\n\n%s"),
272 file_path_utf8, secondary_text);
273 g_free (file_path_utf8);
275 content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (ghidgui->info_bar));
277 icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
278 GTK_ICON_SIZE_DIALOG);
279 gtk_box_pack_start (GTK_BOX (content_area),
280 icon, FALSE, FALSE, 0);
282 label = gtk_label_new ("");
283 gtk_box_pack_start (GTK_BOX (content_area),
284 label, TRUE, TRUE, 6);
286 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
287 gtk_label_set_markup (GTK_LABEL (label), markup);
288 g_free (markup);
290 gtk_misc_set_alignment (GTK_MISC (label), 0., 0.5);
292 gtk_widget_show_all (ghidgui->info_bar);
295 static bool
296 check_externally_modified (void)
298 GFile *file;
299 GFileInfo *info;
300 GTimeVal timeval;
302 /* Treat zero time as a flag to indicate we've not got an mtime yet */
303 if (PCB->Filename == NULL ||
304 (ghidgui->our_mtime.tv_sec == 0 &&
305 ghidgui->our_mtime.tv_usec == 0))
306 return false;
308 file = g_file_new_for_path (PCB->Filename);
309 info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED,
310 G_FILE_QUERY_INFO_NONE, NULL, NULL);
311 g_object_unref (file);
313 if (info == NULL ||
314 !g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED))
315 return false;
317 g_file_info_get_modification_time (info, &timeval); //&ghidgui->last_seen_mtime);
318 g_object_unref (info);
320 /* Ignore when the file on disk is the same age as when we last looked */
321 if (timeval.tv_sec == ghidgui->last_seen_mtime.tv_sec &&
322 timeval.tv_usec == ghidgui->last_seen_mtime.tv_usec)
323 return false;
325 ghidgui->last_seen_mtime = timeval;
327 return (ghidgui->last_seen_mtime.tv_sec > ghidgui->our_mtime.tv_sec) ||
328 (ghidgui->last_seen_mtime.tv_sec == ghidgui->our_mtime.tv_sec &&
329 ghidgui->last_seen_mtime.tv_usec > ghidgui->our_mtime.tv_usec);
332 static gboolean
333 top_window_enter_cb (GtkWidget *widget, GdkEvent *event, GHidPort *port)
335 if (check_externally_modified ())
336 show_file_modified_externally_prompt ();
338 return FALSE;
341 /*! \brief Menu action callback function
342 * \par Function Description
343 * This is the main menu callback function. The callback receives
344 * the original Resource pointer containing the HID actions to be
345 * executed.
347 * All hotkeys go through the menus which means they go through here.
348 * Some, such as tab, are caught by Gtk instead of passed here, so
349 * pcb calls this function directly through ghid_hotkey_cb() for them.
351 * \param [in] The action that was activated
352 * \param [in] The menu resource associated with the action
355 static void
356 ghid_menu_cb (GtkAction *action, const Resource *node)
358 int i;
360 if (action == NULL || node == NULL)
361 return;
363 for (i = 1; i < node->c; i++)
364 if (resource_type (node->v[i]) == 10)
366 #ifdef DEBUG_MENUS
367 printf (" %s\n", node->v[i].value);
368 #endif
369 hid_parse_actions (node->v[i].value);
372 /* Sync gui widgets with pcb state */
373 ghid_update_toggle_flags ();
374 ghid_mode_buttons_update ();
376 /* Sync gui status display with pcb state */
377 AdjustAttachedObjects ();
378 ghid_invalidate_all ();
379 ghid_window_set_name_label (PCB->Name);
380 ghid_set_status_line_label ();
383 /* \brief Accelerator callback for accelerators gtk tries to hide from us */
384 void ghid_hotkey_cb (int which)
386 if (ghid_hotkey_actions[which].action != NULL)
387 ghid_menu_cb (ghid_hotkey_actions[which].action,
388 (gpointer) ghid_hotkey_actions[which].node);
391 static void
392 update_board_mtime_from_disk (void)
394 GFile *file;
395 GFileInfo *info;
397 ghidgui->our_mtime.tv_sec = 0;
398 ghidgui->our_mtime.tv_usec = 0;
399 ghidgui->last_seen_mtime = ghidgui->our_mtime;
401 if (PCB->Filename == NULL)
402 return;
404 file = g_file_new_for_path (PCB->Filename);
405 info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED,
406 G_FILE_QUERY_INFO_NONE, NULL, NULL);
407 g_object_unref (file);
409 if (info == NULL ||
410 !g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED))
411 return;
413 g_file_info_get_modification_time (info, &ghidgui->our_mtime);
414 g_object_unref (info);
416 ghidgui->last_seen_mtime = ghidgui->our_mtime;
419 /* Sync toggle states that were saved with the layout and notify the
420 | config code to update Settings values it manages.
422 void
423 ghid_sync_with_new_layout (void)
425 pcb_use_route_style (&PCB->RouteStyle[0]);
426 ghid_route_style_selector_select_style
427 (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector),
428 &PCB->RouteStyle[0]);
430 ghid_config_handle_units_changed ();
432 ghid_window_set_name_label (PCB->Name);
433 ghid_set_status_line_label ();
434 close_file_modified_externally_prompt ();
435 update_board_mtime_from_disk ();
438 void
439 ghid_notify_save_pcb (const char *filename, bool done)
441 /* Do nothing if it is not the active PCB file that is being saved.
443 if (PCB->Filename == NULL || strcmp (filename, PCB->Filename) != 0)
444 return;
446 if (done)
447 update_board_mtime_from_disk ();
450 void
451 ghid_notify_filename_changed (void)
453 /* Pick up the mtime of the new PCB file */
454 update_board_mtime_from_disk ();
457 /* ---------------------------------------------------------------------------
459 * layer_process()
461 * Takes the index into the layers and produces the text string for
462 * the layer and if the layer is currently visible or not. This is
463 * used by a couple of functions.
466 static void
467 layer_process (gchar **color_string, char **text, int *set, int i)
469 int tmp;
470 char *tmps;
471 gchar *tmpc;
473 /* cheap hack to let users pass in NULL for either text or set if
474 * they don't care about the result
477 if (color_string == NULL)
478 color_string = &tmpc;
480 if (text == NULL)
481 text = &tmps;
483 if (set == NULL)
484 set = &tmp;
486 switch (i)
488 case LAYER_BUTTON_SILK:
489 *color_string = Settings.ElementColor;
490 *text = _( "silk");
491 *set = PCB->ElementOn;
492 break;
493 case LAYER_BUTTON_RATS:
494 *color_string = Settings.RatColor;
495 *text = _( "rat lines");
496 *set = PCB->RatOn;
497 break;
498 case LAYER_BUTTON_PINS:
499 *color_string = Settings.PinColor;
500 *text = _( "pins/pads");
501 *set = PCB->PinOn;
502 break;
503 case LAYER_BUTTON_VIAS:
504 *color_string = Settings.ViaColor;
505 *text = _( "vias");
506 *set = PCB->ViaOn;
507 break;
508 case LAYER_BUTTON_FARSIDE:
509 *color_string = Settings.InvisibleObjectsColor;
510 *text = _( "far side");
511 *set = PCB->InvisibleObjectsOn;
512 break;
513 case LAYER_BUTTON_MASK:
514 *color_string = Settings.MaskColor;
515 *text = _( "solder mask");
516 *set = TEST_FLAG (SHOWMASKFLAG, PCB);
517 break;
518 default: /* layers */
519 *color_string = Settings.LayerColor[i];
520 *text = (char *)UNKNOWN (PCB->Data->Layer[i].Name);
521 *set = PCB->Data->Layer[i].On;
522 break;
526 /*! \brief Callback for GHidLayerSelector layer selection */
527 static void
528 layer_selector_select_callback (GHidLayerSelector *ls, int layer, gpointer d)
530 ignore_layer_update = true;
531 /* Select Layer */
532 PCB->SilkActive = (layer == LAYER_BUTTON_SILK);
533 PCB->RatDraw = (layer == LAYER_BUTTON_RATS);
534 if (layer == LAYER_BUTTON_SILK)
536 PCB->ElementOn = true;
537 hid_action ("LayersChanged");
539 else if (layer == LAYER_BUTTON_RATS)
541 PCB->RatOn = true;
542 hid_action ("LayersChanged");
544 else if (layer < max_copper_layer)
545 ChangeGroupVisibility (layer, TRUE, true);
547 ignore_layer_update = false;
549 ghid_invalidate_all ();
552 /*! \brief Callback for GHidLayerSelector layer renaming */
553 static void
554 layer_selector_rename_callback (GHidLayerSelector *ls,
555 int layer_id,
556 char *new_name,
557 void *userdata)
559 LayerType *layer = LAYER_PTR (layer_id);
561 /* Check for a legal layer name - for now, allow anything non-empty */
562 if (new_name[0] == '\0')
563 return;
565 /* Don't bother if the name is identical to the current one */
566 if (strcmp (layer->Name, new_name) == 0)
567 return;
569 free (layer->Name);
570 layer->Name = strdup (new_name);
571 ghid_layer_buttons_update ();
572 if (!PCB->Changed)
574 SetChangedFlag (true);
575 ghid_window_set_name_label (PCB->Name);
579 /*! \brief Callback for GHidLayerSelector layer toggling */
580 static void
581 layer_selector_toggle_callback (GHidLayerSelector *ls, int layer, gpointer d)
583 gboolean redraw = FALSE;
584 gboolean active;
585 layer_process (NULL, NULL, &active, layer);
587 active = !active;
588 ignore_layer_update = true;
589 switch (layer)
591 case LAYER_BUTTON_SILK:
592 PCB->ElementOn = active;
593 PCB->Data->SILKLAYER.On = PCB->ElementOn;
594 PCB->Data->BACKSILKLAYER.On = PCB->ElementOn;
595 redraw = 1;
596 break;
597 case LAYER_BUTTON_RATS:
598 PCB->RatOn = active;
599 redraw = 1;
600 break;
601 case LAYER_BUTTON_PINS:
602 PCB->PinOn = active;
603 redraw |= (PCB->Data->ElementN != 0);
604 break;
605 case LAYER_BUTTON_VIAS:
606 PCB->ViaOn = active;
607 redraw |= (PCB->Data->ViaN != 0);
608 break;
609 case LAYER_BUTTON_FARSIDE:
610 PCB->InvisibleObjectsOn = active;
611 PCB->Data->BACKSILKLAYER.On = (active && PCB->ElementOn);
612 redraw = TRUE;
613 break;
614 case LAYER_BUTTON_MASK:
615 if (active)
616 SET_FLAG (SHOWMASKFLAG, PCB);
617 else
618 CLEAR_FLAG (SHOWMASKFLAG, PCB);
619 redraw = TRUE;
620 break;
621 default:
622 /* Flip the visibility */
623 ChangeGroupVisibility (layer, active, false);
624 redraw = TRUE;
625 break;
628 /* Select the next visible layer. (If there is none, this will
629 * select the currently-selected layer, triggering the selection
630 * callback, which will turn the visibility on.) This way we
631 * will never have an invisible layer selected.
633 if (!active)
634 ghid_layer_selector_select_next_visible (ls);
636 ignore_layer_update = false;
638 if (redraw)
639 ghid_invalidate_all();
642 /*! \brief Install menu bar and accelerator groups */
643 void
644 ghid_install_accel_groups (GtkWindow *window, GhidGui *gui)
646 gtk_window_add_accel_group
647 (window, ghid_main_menu_get_accel_group
648 (GHID_MAIN_MENU (gui->menu_bar)));
649 gtk_window_add_accel_group
650 (window, ghid_layer_selector_get_accel_group
651 (GHID_LAYER_SELECTOR (gui->layer_selector)));
652 gtk_window_add_accel_group
653 (window, ghid_route_style_selector_get_accel_group
654 (GHID_ROUTE_STYLE_SELECTOR (gui->route_style_selector)));
657 /*! \brief Remove menu bar and accelerator groups */
658 void
659 ghid_remove_accel_groups (GtkWindow *window, GhidGui *gui)
661 gtk_window_remove_accel_group
662 (window, ghid_main_menu_get_accel_group
663 (GHID_MAIN_MENU (gui->menu_bar)));
664 gtk_window_remove_accel_group
665 (window, ghid_layer_selector_get_accel_group
666 (GHID_LAYER_SELECTOR (gui->layer_selector)));
667 gtk_window_remove_accel_group
668 (window, ghid_route_style_selector_get_accel_group
669 (GHID_ROUTE_STYLE_SELECTOR (gui->route_style_selector)));
672 /* Refreshes the window title bar and sets the PCB name to the
673 * window title bar or to a seperate label
675 void
676 ghid_window_set_name_label (gchar * name)
678 gchar *str;
679 gchar *filename;
681 /* FIXME -- should this happen? It does... */
682 /* This happens if we're calling an exporter from the command line */
683 if (ghidgui == NULL)
684 return;
686 dup_string (&(ghidgui->name_label_string), name);
687 if (!ghidgui->name_label_string || !*ghidgui->name_label_string)
688 ghidgui->name_label_string = g_strdup (_("Unnamed"));
690 if (!PCB->Filename || !*PCB->Filename)
691 filename = g_strdup(_("Unsaved.pcb"));
692 else
693 filename = g_strdup(PCB->Filename);
695 str = g_strdup_printf ("%s%s (%s) - PCB", PCB->Changed ? "*": "",
696 ghidgui->name_label_string, filename);
697 gtk_window_set_title (GTK_WINDOW (gport->top_window), str);
698 g_free (str);
699 g_free (filename);
702 static void
703 grid_units_button_cb (GtkWidget * widget, gpointer data)
705 /* Button only toggles between mm and mil */
706 if (Settings.grid_unit == get_unit_struct ("mm"))
707 hid_actionl ("SetUnits", "mil", NULL);
708 else
709 hid_actionl ("SetUnits", "mm", NULL);
713 * The two following callbacks are used to keep the absolute
714 * and relative cursor labels from growing and shrinking as you
715 * move the cursor around.
717 static void
718 absolute_label_size_req_cb (GtkWidget * widget,
719 GtkRequisition *req, gpointer data)
722 static gint w = 0;
723 if (req->width > w)
724 w = req->width;
725 else
726 req->width = w;
729 static void
730 relative_label_size_req_cb (GtkWidget * widget,
731 GtkRequisition *req, gpointer data)
734 static gint w = 0;
735 if (req->width > w)
736 w = req->width;
737 else
738 req->width = w;
741 static void
742 make_cursor_position_labels (GtkWidget * hbox, GHidPort * port)
744 GtkWidget *frame, *label;
746 /* The grid units button next to the cursor position labels.
748 ghidgui->grid_units_button = gtk_button_new ();
749 label = gtk_label_new ("");
750 gtk_label_set_markup (GTK_LABEL (label),
751 Settings.grid_unit->in_suffix);
752 ghidgui->grid_units_label = label;
753 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
754 gtk_container_add (GTK_CONTAINER (ghidgui->grid_units_button), label);
755 gtk_box_pack_end (GTK_BOX (hbox), ghidgui->grid_units_button, FALSE, TRUE, 0);
756 g_signal_connect (ghidgui->grid_units_button, "clicked",
757 G_CALLBACK (grid_units_button_cb), NULL);
759 /* The absolute cursor position label
761 frame = gtk_frame_new (NULL);
762 gtk_box_pack_end (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
763 gtk_container_set_border_width (GTK_CONTAINER (frame), 2);
764 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
766 label = gtk_label_new ("");
767 gtk_container_add (GTK_CONTAINER (frame), label);
768 ghidgui->cursor_position_absolute_label = label;
769 g_signal_connect (G_OBJECT (label), "size-request",
770 G_CALLBACK (absolute_label_size_req_cb), NULL);
773 /* The relative cursor position label
775 frame = gtk_frame_new (NULL);
776 gtk_box_pack_end (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
777 gtk_container_set_border_width (GTK_CONTAINER (frame), 2);
778 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
779 label = gtk_label_new (" __.__ __.__ ");
780 gtk_container_add (GTK_CONTAINER (frame), label);
781 ghidgui->cursor_position_relative_label = label;
782 g_signal_connect (G_OBJECT (label), "size-request",
783 G_CALLBACK (relative_label_size_req_cb), NULL);
787 /* \brief Add "virtual layers" to a layer selector */
788 static void
789 make_virtual_layer_buttons (GtkWidget *layer_selector)
791 GHidLayerSelector *layersel = GHID_LAYER_SELECTOR (layer_selector);
792 gchar *text;
793 gchar *color_string;
794 gboolean active;
796 layer_process (&color_string, &text, &active, LAYER_BUTTON_SILK);
797 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_SILK,
798 text, color_string, active, TRUE, FALSE);
799 layer_process (&color_string, &text, &active, LAYER_BUTTON_RATS);
800 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_RATS,
801 text, color_string, active, TRUE, FALSE);
802 layer_process (&color_string, &text, &active, LAYER_BUTTON_PINS);
803 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_PINS,
804 text, color_string, active, FALSE, FALSE);
805 layer_process (&color_string, &text, &active, LAYER_BUTTON_VIAS);
806 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_VIAS,
807 text, color_string, active, FALSE, FALSE);
808 layer_process (&color_string, &text, &active, LAYER_BUTTON_FARSIDE);
809 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_FARSIDE,
810 text, color_string, active, FALSE, FALSE);
811 layer_process (&color_string, &text, &active, LAYER_BUTTON_MASK);
812 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_MASK,
813 text, color_string, active, FALSE, FALSE);
816 /*! \brief callback for ghid_layer_selector_update_colors */
817 const gchar *
818 get_layer_color (gint layer)
820 gchar *rv;
821 layer_process (&rv, NULL, NULL, layer);
822 return rv;
825 /*! \brief Update a layer selector's color scheme */
826 void
827 ghid_layer_buttons_color_update (void)
829 ghid_layer_selector_update_colors
830 (GHID_LAYER_SELECTOR (ghidgui->layer_selector), get_layer_color);
831 pcb_colors_from_settings (PCB);
834 /*! \brief Populate a layer selector with all layers Gtk is aware of */
835 static void
836 make_layer_buttons (GtkWidget *layersel)
838 gint i;
839 gchar *text;
840 gchar *color_string;
841 gboolean active = TRUE;
843 for (i = 0; i < max_copper_layer; ++i)
845 layer_process (&color_string, &text, &active, i);
846 ghid_layer_selector_add_layer (GHID_LAYER_SELECTOR (layersel), i,
847 text, color_string, active, TRUE, TRUE);
852 /*! \brief callback for ghid_layer_selector_delete_layers */
853 gboolean
854 get_layer_delete (gint layer)
856 return layer >= max_copper_layer;
859 /*! \brief Synchronize layer selector widget with current PCB state
860 * \par Function Description
861 * Called when user toggles layer visibility or changes drawing layer,
862 * or when layer visibility is changed programatically.
864 void
865 ghid_layer_buttons_update (void)
867 gint layer;
869 if (ignore_layer_update)
870 return;
872 ghid_layer_selector_delete_layers
873 (GHID_LAYER_SELECTOR (ghidgui->layer_selector),
874 get_layer_delete);
875 make_layer_buttons (ghidgui->layer_selector);
876 make_virtual_layer_buttons (ghidgui->layer_selector);
877 ghid_main_menu_install_layer_selector
878 (GHID_MAIN_MENU (ghidgui->menu_bar),
879 GHID_LAYER_SELECTOR (ghidgui->layer_selector));
881 /* Sync selected layer with PCB's state */
882 if (PCB->RatDraw)
883 layer = LAYER_BUTTON_RATS;
884 else if (PCB->SilkActive)
885 layer = LAYER_BUTTON_SILK;
886 else
887 layer = LayerStack[0];
889 ghid_layer_selector_select_layer
890 (GHID_LAYER_SELECTOR (ghidgui->layer_selector), layer);
893 /*! \brief Called when user clicks OK on route style dialog */
894 static void
895 route_styles_edited_cb (GHidRouteStyleSelector *rss, gboolean save,
896 gpointer data)
898 if (save)
900 g_free (Settings.Routes);
901 Settings.Routes = make_route_string (PCB->RouteStyle, NUM_STYLES);
902 ghidgui->config_modified = TRUE;
903 ghid_config_files_write ();
905 ghid_main_menu_install_route_style_selector
906 (GHID_MAIN_MENU (ghidgui->menu_bar),
907 GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
910 /*! \brief Called when a route style is selected */
911 static void
912 route_style_changed_cb (GHidRouteStyleSelector *rss, RouteStyleType *rst,
913 gpointer data)
915 pcb_use_route_style (rst);
916 ghid_set_status_line_label();
919 /*! \brief Configure the route style selector */
920 void
921 make_route_style_buttons (GHidRouteStyleSelector *rss)
923 int i;
924 for (i = 0; i < NUM_STYLES; ++i)
925 ghid_route_style_selector_add_route_style (rss, &PCB->RouteStyle[i]);
926 g_signal_connect (G_OBJECT (rss), "select_style",
927 G_CALLBACK (route_style_changed_cb), NULL);
928 g_signal_connect (G_OBJECT (rss), "style_edited",
929 G_CALLBACK (route_styles_edited_cb), NULL);
930 ghid_main_menu_install_route_style_selector
931 (GHID_MAIN_MENU (ghidgui->menu_bar),
932 GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
936 * ---------------------------------------------------------------
937 * Mode buttons
939 typedef struct
941 GtkWidget *button;
942 GtkWidget *toolbar_button;
943 guint button_cb_id;
944 guint toolbar_button_cb_id;
945 gchar *name;
946 gint mode;
947 gchar **xpm;
949 ModeButton;
952 static ModeButton mode_buttons[] = {
953 {NULL, NULL, 0, 0, "via", VIA_MODE, via},
954 {NULL, NULL, 0, 0, "line", LINE_MODE, line},
955 {NULL, NULL, 0, 0, "arc", ARC_MODE, arc},
956 {NULL, NULL, 0, 0, "text", TEXT_MODE, text},
957 {NULL, NULL, 0, 0, "rectangle", RECTANGLE_MODE, rect},
958 {NULL, NULL, 0, 0, "polygon", POLYGON_MODE, poly},
959 {NULL, NULL, 0, 0, "polygonhole", POLYGONHOLE_MODE, polyhole},
960 {NULL, NULL, 0, 0, "buffer", PASTEBUFFER_MODE, buf},
961 {NULL, NULL, 0, 0, "remove", REMOVE_MODE, del},
962 {NULL, NULL, 0, 0, "rotate", ROTATE_MODE, rot},
963 {NULL, NULL, 0, 0, "insertPoint", INSERTPOINT_MODE, ins},
964 {NULL, NULL, 0, 0, "thermal", THERMAL_MODE, thrm},
965 {NULL, NULL, 0, 0, "select", ARROW_MODE, sel},
966 {NULL, NULL, 0, 0, "lock", LOCK_MODE, lock}
969 static gint n_mode_buttons = G_N_ELEMENTS (mode_buttons);
971 static void
972 do_set_mode (int mode)
974 SetMode (mode);
975 ghid_mode_cursor (mode);
976 ghidgui->settings_mode = mode;
979 static void
980 mode_toolbar_button_toggled_cb (GtkToggleButton *button, ModeButton * mb)
982 gboolean active = gtk_toggle_button_get_active (button);
984 if (mb->button != NULL)
986 g_signal_handler_block (mb->button, mb->button_cb_id);
987 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->button), active);
988 g_signal_handler_unblock (mb->button, mb->button_cb_id);
991 if (active)
992 do_set_mode (mb->mode);
995 static void
996 mode_button_toggled_cb (GtkWidget * widget, ModeButton * mb)
998 gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
1000 if (mb->toolbar_button != NULL)
1002 g_signal_handler_block (mb->toolbar_button, mb->toolbar_button_cb_id);
1003 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->toolbar_button), active);
1004 g_signal_handler_unblock (mb->toolbar_button, mb->toolbar_button_cb_id);
1007 if (active)
1008 do_set_mode (mb->mode);
1011 void
1012 ghid_mode_buttons_update (void)
1014 ModeButton *mb;
1015 gint i;
1017 for (i = 0; i < n_mode_buttons; ++i)
1019 mb = &mode_buttons[i];
1020 if (Settings.Mode == mb->mode)
1022 g_signal_handler_block (mb->button, mb->button_cb_id);
1023 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->button), TRUE);
1024 g_signal_handler_unblock (mb->button, mb->button_cb_id);
1026 g_signal_handler_block (mb->toolbar_button, mb->toolbar_button_cb_id);
1027 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->toolbar_button), TRUE);
1028 g_signal_handler_unblock (mb->toolbar_button, mb->toolbar_button_cb_id);
1029 break;
1034 void
1035 ghid_pack_mode_buttons (void)
1037 if (ghidgui->compact_vertical)
1039 gtk_widget_hide (ghidgui->mode_buttons_frame);
1040 gtk_widget_show_all (ghidgui->mode_toolbar);
1042 else
1044 gtk_widget_hide (ghidgui->mode_toolbar);
1045 gtk_widget_show_all (ghidgui->mode_buttons_frame);
1049 static void
1050 make_mode_buttons_and_toolbar (GtkWidget **mode_frame,
1051 GtkWidget **mode_toolbar)
1053 GtkToolItem *tool_item;
1054 GtkWidget *vbox, *hbox = NULL;
1055 GtkWidget *image;
1056 GdkPixbuf *pixbuf;
1057 GSList *group = NULL;
1058 GSList *toolbar_group = NULL;
1059 ModeButton *mb;
1060 int i;
1062 *mode_toolbar = gtk_toolbar_new ();
1064 *mode_frame = gtk_frame_new (NULL);
1065 vbox = gtk_vbox_new (FALSE, 0);
1066 gtk_container_add (GTK_CONTAINER (*mode_frame), vbox);
1068 for (i = 0; i < n_mode_buttons; ++i)
1070 mb = &mode_buttons[i];
1072 /* Create tool button for mode frame */
1073 mb->button = gtk_radio_button_new (group);
1074 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (mb->button));
1075 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (mb->button), FALSE);
1077 /* Create tool button for toolbar */
1078 mb->toolbar_button = gtk_radio_button_new (toolbar_group);
1079 toolbar_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (mb->toolbar_button));
1080 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (mb->toolbar_button), FALSE);
1082 /* Pack mode-frame button into the frame */
1083 if ((i % ghidgui->n_mode_button_columns) == 0)
1085 hbox = gtk_hbox_new (FALSE, 0);
1086 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1088 gtk_box_pack_start (GTK_BOX (hbox), mb->button, FALSE, FALSE, 0);
1090 /* Create a container for the toolbar button and add that */
1091 tool_item = gtk_tool_item_new ();
1092 gtk_container_add (GTK_CONTAINER (tool_item), mb->toolbar_button);
1093 gtk_toolbar_insert (GTK_TOOLBAR (*mode_toolbar), tool_item, -1);
1095 /* Load the image for the button, create GtkImage widgets for both
1096 * the grid button and the toolbar button, then pack into the buttons
1098 pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **) mb->xpm);
1099 image = gtk_image_new_from_pixbuf (pixbuf);
1100 gtk_container_add (GTK_CONTAINER (mb->button), image);
1101 image = gtk_image_new_from_pixbuf (pixbuf);
1102 gtk_container_add (GTK_CONTAINER (mb->toolbar_button), image);
1103 g_object_unref (pixbuf);
1105 if (strcmp (mb->name, "select") == 0)
1107 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->button), TRUE);
1108 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->toolbar_button), TRUE);
1111 mb->button_cb_id =
1112 g_signal_connect (mb->button, "toggled",
1113 G_CALLBACK (mode_button_toggled_cb), mb);
1114 mb->toolbar_button_cb_id =
1115 g_signal_connect (mb->toolbar_button, "toggled",
1116 G_CALLBACK (mode_toolbar_button_toggled_cb), mb);
1122 * ---------------------------------------------------------------
1123 * Top window
1124 * ---------------------------------------------------------------
1127 static gint
1128 delete_chart_cb (GtkWidget * widget, GdkEvent * event, GHidPort * port)
1130 ghid_config_files_write ();
1131 hid_action ("Quit");
1134 * Return TRUE to keep our app running. A FALSE here would let the
1135 * delete signal continue on and kill our program.
1137 return TRUE;
1140 static void
1141 destroy_chart_cb (GtkWidget * widget, GHidPort * port)
1143 ghid_shutdown_renderer (port);
1144 gtk_main_quit ();
1147 static void
1148 get_widget_styles (GtkStyle **menu_bar_style,
1149 GtkStyle **tool_button_style,
1150 GtkStyle **tool_button_label_style)
1152 GtkWidget *tool_button;
1153 GtkWidget *tool_button_label;
1154 GtkToolItem *tool_item;
1156 /* Build a tool item to extract the theme's styling for a toolbar button with text */
1157 tool_item = gtk_tool_item_new ();
1158 gtk_toolbar_insert (GTK_TOOLBAR (ghidgui->mode_toolbar), tool_item, 0);
1159 tool_button = gtk_button_new ();
1160 gtk_container_add (GTK_CONTAINER (tool_item), tool_button);
1161 tool_button_label = gtk_label_new ("");
1162 gtk_container_add (GTK_CONTAINER (tool_button), tool_button_label);
1164 /* Grab the various styles we need */
1165 gtk_widget_ensure_style (ghidgui->menu_bar);
1166 *menu_bar_style = gtk_widget_get_style (ghidgui->menu_bar);
1168 gtk_widget_ensure_style (tool_button);
1169 *tool_button_style = gtk_widget_get_style (tool_button);
1171 gtk_widget_ensure_style (tool_button_label);
1172 *tool_button_label_style = gtk_widget_get_style (tool_button_label);
1174 gtk_widget_destroy (GTK_WIDGET (tool_item));
1177 static void
1178 do_fix_topbar_theming (void)
1180 GtkWidget *rel_pos_frame;
1181 GtkWidget *abs_pos_frame;
1182 GtkStyle *menu_bar_style;
1183 GtkStyle *tool_button_style;
1184 GtkStyle *tool_button_label_style;
1186 get_widget_styles (&menu_bar_style,
1187 &tool_button_style,
1188 &tool_button_label_style);
1190 /* Style the top bar background as if it were all a menu bar */
1191 gtk_widget_set_style (ghidgui->top_bar_background, menu_bar_style);
1193 /* Style the cursor position labels using the menu bar style as well.
1194 * If this turns out to cause problems with certain gtk themes, we may
1195 * need to grab the GtkStyle associated with an actual menu item to
1196 * get a text color to render with.
1198 gtk_widget_set_style (ghidgui->cursor_position_relative_label, menu_bar_style);
1199 gtk_widget_set_style (ghidgui->cursor_position_absolute_label, menu_bar_style);
1201 /* Style the units button as if it were a toolbar button - hopefully
1202 * this isn't too ugly sitting on a background themed as a menu bar.
1203 * It is unlikely any theme defines colours for a GtkButton sitting on
1204 * a menu bar.
1206 rel_pos_frame = gtk_widget_get_parent (ghidgui->cursor_position_relative_label);
1207 abs_pos_frame = gtk_widget_get_parent (ghidgui->cursor_position_absolute_label);
1208 gtk_widget_set_style (rel_pos_frame, menu_bar_style);
1209 gtk_widget_set_style (abs_pos_frame, menu_bar_style);
1210 gtk_widget_set_style (ghidgui->grid_units_button, tool_button_style);
1211 gtk_widget_set_style (ghidgui->grid_units_label, tool_button_label_style);
1214 /* Attempt to produce a conststent style for our extra menu-bar items by
1215 * copying aspects from the menu bar style set by the user's GTK theme.
1216 * Setup signal handlers to update our efforts if the user changes their
1217 * theme whilst we are running.
1219 static void
1220 fix_topbar_theming (void)
1222 GtkSettings *settings;
1224 do_fix_topbar_theming ();
1226 settings = gtk_widget_get_settings (ghidgui->top_bar_background);
1227 g_signal_connect (settings, "notify::gtk-theme-name",
1228 G_CALLBACK (do_fix_topbar_theming), NULL);
1229 g_signal_connect (settings, "notify::gtk-font-name",
1230 G_CALLBACK (do_fix_topbar_theming), NULL);
1234 * Create the top_window contents. The config settings should be loaded
1235 * before this is called.
1237 static void
1238 ghid_build_pcb_top_window (void)
1240 GtkWidget *window;
1241 GtkWidget *vbox_main, *hbox_middle, *hbox;
1242 GtkWidget *vbox, *frame;
1243 GtkWidget *label;
1244 GHidPort *port = &ghid_port;
1245 GtkWidget *scrolled;
1247 window = gport->top_window;
1249 vbox_main = gtk_vbox_new (FALSE, 0);
1250 gtk_container_add (GTK_CONTAINER (window), vbox_main);
1252 /* -- Top control bar */
1253 ghidgui->top_bar_background = gtk_event_box_new ();
1254 gtk_box_pack_start (GTK_BOX (vbox_main),
1255 ghidgui->top_bar_background, FALSE, FALSE, 0);
1257 ghidgui->top_hbox = gtk_hbox_new (FALSE, 4);
1258 gtk_container_add (GTK_CONTAINER (ghidgui->top_bar_background),
1259 ghidgui->top_hbox);
1262 * menu_hbox will be made insensitive when the gui needs
1263 * a modal button GetLocation button press.
1265 ghidgui->menu_hbox = gtk_hbox_new (FALSE, 0);
1266 gtk_box_pack_start (GTK_BOX (ghidgui->top_hbox), ghidgui->menu_hbox,
1267 FALSE, FALSE, 0);
1269 ghidgui->menubar_toolbar_vbox = gtk_vbox_new (FALSE, 0);
1270 gtk_box_pack_start (GTK_BOX (ghidgui->menu_hbox),
1271 ghidgui->menubar_toolbar_vbox, FALSE, FALSE, 0);
1273 /* Build layer menus */
1274 ghidgui->layer_selector = ghid_layer_selector_new ();
1275 make_layer_buttons (ghidgui->layer_selector);
1276 make_virtual_layer_buttons (ghidgui->layer_selector);
1277 g_signal_connect (G_OBJECT (ghidgui->layer_selector), "select-layer",
1278 G_CALLBACK (layer_selector_select_callback),
1279 NULL);
1280 g_signal_connect (G_OBJECT (ghidgui->layer_selector), "toggle-layer",
1281 G_CALLBACK (layer_selector_toggle_callback),
1282 NULL);
1283 g_signal_connect (G_OBJECT (ghidgui->layer_selector), "rename-layer",
1284 G_CALLBACK (layer_selector_rename_callback),
1285 NULL);
1286 /* Build main menu */
1287 ghidgui->menu_bar = ghid_load_menus ();
1288 gtk_box_pack_start (GTK_BOX (ghidgui->menubar_toolbar_vbox),
1289 ghidgui->menu_bar, FALSE, FALSE, 0);
1291 make_mode_buttons_and_toolbar (&ghidgui->mode_buttons_frame,
1292 &ghidgui->mode_toolbar);
1293 gtk_box_pack_start (GTK_BOX (ghidgui->menubar_toolbar_vbox),
1294 ghidgui->mode_toolbar, FALSE, FALSE, 0);
1297 ghidgui->position_hbox = gtk_hbox_new (FALSE, 0);
1298 gtk_box_pack_end (GTK_BOX(ghidgui->top_hbox),
1299 ghidgui->position_hbox, FALSE, FALSE, 4);
1301 make_cursor_position_labels (ghidgui->position_hbox, port);
1303 hbox_middle = gtk_hbox_new (FALSE, 0);
1304 gtk_box_pack_start (GTK_BOX (vbox_main), hbox_middle, TRUE, TRUE, 3);
1306 fix_topbar_theming (); /* Must be called after toolbar is created */
1308 /* -- Left control bar */
1310 * This box will be made insensitive when the gui needs
1311 * a modal button GetLocation button press.
1313 ghidgui->left_toolbar = gtk_vbox_new (FALSE, 0);
1314 gtk_box_pack_start (GTK_BOX (hbox_middle),
1315 ghidgui->left_toolbar, FALSE, FALSE, 3);
1317 vbox = ghid_scrolled_vbox (ghidgui->left_toolbar, &scrolled,
1318 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1319 gtk_box_pack_start (GTK_BOX(vbox), ghidgui->layer_selector,
1320 FALSE, FALSE, 0);
1322 /* ghidgui->mode_buttons_frame was created above in the call to
1323 * make_mode_buttons_and_toolbar (...);
1325 gtk_box_pack_start (GTK_BOX (ghidgui->left_toolbar),
1326 ghidgui->mode_buttons_frame, FALSE, FALSE, 0);
1328 frame = gtk_frame_new(NULL);
1329 gtk_box_pack_end (GTK_BOX (ghidgui->left_toolbar), frame, FALSE, FALSE, 0);
1330 vbox = gtk_vbox_new(FALSE, 0);
1331 gtk_container_add(GTK_CONTAINER(frame), vbox);
1332 hbox = gtk_hbox_new(FALSE, 0);
1333 gtk_box_pack_start(GTK_BOX (vbox), hbox, FALSE, FALSE, 1);
1334 ghidgui->route_style_selector = ghid_route_style_selector_new ();
1335 make_route_style_buttons
1336 (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
1337 gtk_box_pack_start(GTK_BOX(hbox), ghidgui->route_style_selector,
1338 FALSE, FALSE, 4);
1340 ghidgui->vbox_middle = gtk_vbox_new (FALSE, 0);
1341 gtk_box_pack_start (GTK_BOX (hbox_middle),
1342 ghidgui->vbox_middle, TRUE, TRUE, 0);
1344 hbox = gtk_hbox_new (FALSE, 0);
1345 gtk_box_pack_start (GTK_BOX (ghidgui->vbox_middle), hbox, TRUE, TRUE, 0);
1347 /* -- The PCB layout output drawing area */
1349 gport->drawing_area = gtk_drawing_area_new ();
1350 ghid_init_drawing_widget (gport->drawing_area, gport);
1352 gtk_widget_add_events (gport->drawing_area, GDK_EXPOSURE_MASK
1353 | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
1354 | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK
1355 | GDK_KEY_RELEASE_MASK | GDK_KEY_PRESS_MASK
1356 | GDK_FOCUS_CHANGE_MASK | GDK_POINTER_MOTION_MASK
1357 | GDK_POINTER_MOTION_HINT_MASK);
1360 * This is required to get the drawing_area key-press-event. Also the
1361 * enter and button press callbacks grab focus to be sure we have it
1362 * when in the drawing_area.
1364 gtk_widget_set_can_focus (gport->drawing_area, TRUE);
1366 gtk_box_pack_start (GTK_BOX (hbox), gport->drawing_area, TRUE, TRUE, 0);
1368 ghidgui->v_adjustment = gtk_adjustment_new (0.0, 0.0, 100.0,
1369 10.0, 10.0, 10.0);
1370 ghidgui->v_range =
1371 gtk_vscrollbar_new (GTK_ADJUSTMENT (ghidgui->v_adjustment));
1373 gtk_box_pack_start (GTK_BOX (hbox), ghidgui->v_range, FALSE, FALSE, 0);
1375 g_signal_connect (G_OBJECT (ghidgui->v_adjustment), "value_changed",
1376 G_CALLBACK (v_adjustment_changed_cb), ghidgui);
1378 ghidgui->h_adjustment = gtk_adjustment_new (0.0, 0.0, 100.0,
1379 10.0, 10.0, 10.0);
1380 ghidgui->h_range =
1381 gtk_hscrollbar_new (GTK_ADJUSTMENT (ghidgui->h_adjustment));
1382 gtk_box_pack_start (GTK_BOX (ghidgui->vbox_middle),
1383 ghidgui->h_range, FALSE, FALSE, 0);
1385 g_signal_connect (G_OBJECT (ghidgui->h_adjustment), "value_changed",
1386 G_CALLBACK (h_adjustment_changed_cb), ghidgui);
1388 /* -- The bottom status line label */
1389 ghidgui->status_line_hbox = gtk_hbox_new (FALSE, 0);
1390 gtk_box_pack_start (GTK_BOX (ghidgui->vbox_middle),
1391 ghidgui->status_line_hbox, FALSE, FALSE, 2);
1393 label = gtk_label_new ("");
1394 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
1395 gtk_box_pack_start (GTK_BOX (ghidgui->status_line_hbox), label, FALSE,
1396 FALSE, 0);
1397 ghidgui->status_line_label = label;
1399 /* Depending on user setting, the command_combo_box may get packed into
1400 | the status_line_hbox, but it will happen on demand the first time
1401 | the user does a command entry.
1404 g_signal_connect (G_OBJECT (gport->drawing_area), "realize",
1405 G_CALLBACK (ghid_port_drawing_realize_cb),
1406 port);
1407 g_signal_connect (G_OBJECT (gport->drawing_area), "expose_event",
1408 G_CALLBACK (ghid_drawing_area_expose_cb),
1409 port);
1410 g_signal_connect (G_OBJECT (gport->top_window), "configure_event",
1411 G_CALLBACK (top_window_configure_event_cb), port);
1412 g_signal_connect (gport->top_window, "enter-notify-event",
1413 G_CALLBACK (top_window_enter_cb), port);
1414 g_signal_connect (G_OBJECT (gport->drawing_area), "configure_event",
1415 G_CALLBACK (ghid_port_drawing_area_configure_event_cb),
1416 port);
1419 /* Mouse and key events will need to be intercepted when PCB needs a
1420 | location from the user.
1423 ghid_interface_input_signals_connect ();
1425 g_signal_connect (G_OBJECT (gport->drawing_area), "scroll_event",
1426 G_CALLBACK (ghid_port_window_mouse_scroll_cb), port);
1427 g_signal_connect (G_OBJECT (gport->drawing_area), "enter_notify_event",
1428 G_CALLBACK (ghid_port_window_enter_cb), port);
1429 g_signal_connect (G_OBJECT (gport->drawing_area), "leave_notify_event",
1430 G_CALLBACK (ghid_port_window_leave_cb), port);
1431 g_signal_connect (G_OBJECT (gport->drawing_area), "motion_notify_event",
1432 G_CALLBACK (ghid_port_window_motion_cb), port);
1436 g_signal_connect (G_OBJECT (window), "delete_event",
1437 G_CALLBACK (delete_chart_cb), port);
1438 g_signal_connect (G_OBJECT (window), "destroy",
1439 G_CALLBACK (destroy_chart_cb), port);
1441 ghidgui->creating = FALSE;
1443 gtk_widget_show_all (gport->top_window);
1444 ghid_pack_mode_buttons ();
1445 gdk_window_set_back_pixmap (gtk_widget_get_window (gport->drawing_area),
1446 NULL, FALSE);
1450 /* Connect and disconnect just the signals a g_main_loop() will need.
1451 | Cursor and motion events still need to be handled by the top level
1452 | loop, so don't connect/reconnect these.
1453 | A g_main_loop will be running when PCB wants the user to select a
1454 | location or if command entry is needed in the status line hbox.
1455 | During these times normal button/key presses are intercepted, either
1456 | by new signal handlers or the command_combo_box entry.
1458 static gulong button_press_handler, button_release_handler,
1459 key_press_handler, key_release_handler;
1461 void
1462 ghid_interface_input_signals_connect (void)
1464 button_press_handler =
1465 g_signal_connect (G_OBJECT (gport->drawing_area), "button_press_event",
1466 G_CALLBACK (ghid_port_button_press_cb), NULL);
1468 button_release_handler =
1469 g_signal_connect (G_OBJECT (gport->drawing_area), "button_release_event",
1470 G_CALLBACK (ghid_port_button_release_cb), NULL);
1472 key_press_handler =
1473 g_signal_connect (G_OBJECT (gport->drawing_area), "key_press_event",
1474 G_CALLBACK (ghid_port_key_press_cb), NULL);
1476 key_release_handler =
1477 g_signal_connect (G_OBJECT (gport->drawing_area), "key_release_event",
1478 G_CALLBACK (ghid_port_key_release_cb), NULL);
1481 void
1482 ghid_interface_input_signals_disconnect (void)
1484 if (button_press_handler)
1485 g_signal_handler_disconnect (gport->drawing_area, button_press_handler);
1487 if (button_release_handler)
1488 g_signal_handler_disconnect (gport->drawing_area, button_release_handler);
1490 if (key_press_handler)
1491 g_signal_handler_disconnect (gport->drawing_area, key_press_handler);
1493 if (key_release_handler)
1494 g_signal_handler_disconnect (gport->drawing_area, key_release_handler);
1496 button_press_handler = button_release_handler = 0;
1497 key_press_handler = key_release_handler = 0;
1502 /* We'll set the interface insensitive when a g_main_loop is running so the
1503 | Gtk menus and buttons don't respond and interfere with the special entry
1504 | the user needs to be doing.
1506 void
1507 ghid_interface_set_sensitive (gboolean sensitive)
1509 gtk_widget_set_sensitive (ghidgui->left_toolbar, sensitive);
1510 gtk_widget_set_sensitive (ghidgui->menu_hbox, sensitive);
1514 /* ----------------------------------------------------------------------
1515 * initializes icon pixmap and also cursor bit maps
1517 static void
1518 ghid_init_icons (GHidPort * port)
1520 GdkWindow *window = gtk_widget_get_window (gport->top_window);
1522 XC_clock_source = gdk_bitmap_create_from_data (window,
1523 (char *) rotateIcon_bits,
1524 rotateIcon_width,
1525 rotateIcon_height);
1526 XC_clock_mask =
1527 gdk_bitmap_create_from_data (window, (char *) rotateMask_bits,
1528 rotateMask_width, rotateMask_height);
1530 XC_hand_source = gdk_bitmap_create_from_data (window,
1531 (char *) handIcon_bits,
1532 handIcon_width,
1533 handIcon_height);
1534 XC_hand_mask =
1535 gdk_bitmap_create_from_data (window, (char *) handMask_bits,
1536 handMask_width, handMask_height);
1538 XC_lock_source = gdk_bitmap_create_from_data (window,
1539 (char *) lockIcon_bits,
1540 lockIcon_width,
1541 lockIcon_height);
1542 XC_lock_mask =
1543 gdk_bitmap_create_from_data (window, (char *) lockMask_bits,
1544 lockMask_width, lockMask_height);
1547 void
1548 ghid_create_pcb_widgets (void)
1550 GHidPort *port = &ghid_port;
1551 GError *err = NULL;
1553 if (bg_image_file)
1554 ghidgui->bg_pixbuf = gdk_pixbuf_new_from_file(bg_image_file, &err);
1555 if (err)
1557 g_error("%s", err->message);
1558 g_error_free(err);
1560 ghid_build_pcb_top_window ();
1561 ghid_install_accel_groups (GTK_WINDOW (port->top_window), ghidgui);
1562 ghid_update_toggle_flags ();
1564 ghid_init_icons (port);
1565 SetMode (ARROW_MODE);
1566 ghid_mode_buttons_update ();
1569 static gboolean
1570 ghid_listener_cb (GIOChannel *source,
1571 GIOCondition condition,
1572 gpointer data)
1574 GIOStatus status;
1575 gchar *str;
1576 gsize len;
1577 gsize term;
1578 GError *err = NULL;
1581 if (condition & G_IO_HUP)
1583 gui->log ("Read end of pipe died!\n");
1584 return FALSE;
1587 if (condition == G_IO_IN)
1589 status = g_io_channel_read_line (source, &str, &len, &term, &err);
1590 switch (status)
1592 case G_IO_STATUS_NORMAL:
1593 hid_parse_actions (str);
1594 g_free (str);
1595 break;
1597 case G_IO_STATUS_ERROR:
1598 gui->log ("ERROR status from g_io_channel_read_line\n");
1599 return FALSE;
1600 break;
1602 case G_IO_STATUS_EOF:
1603 gui->log ("Input pipe returned EOF. The --listen option is \n"
1604 "probably not running anymore in this session.\n");
1605 return FALSE;
1606 break;
1608 case G_IO_STATUS_AGAIN:
1609 gui->log ("AGAIN status from g_io_channel_read_line\n");
1610 return FALSE;
1611 break;
1613 default:
1614 fprintf (stderr, "ERROR: unhandled case in ghid_listener_cb\n");
1615 return FALSE;
1616 break;
1620 else
1621 fprintf (stderr, "Unknown condition in ghid_listener_cb\n");
1623 return TRUE;
1626 static void
1627 ghid_create_listener (void)
1629 GIOChannel *channel;
1630 int fd = fileno (stdin);
1632 channel = g_io_channel_unix_new (fd);
1633 g_io_add_watch (channel, G_IO_IN, ghid_listener_cb, NULL);
1637 /* ------------------------------------------------------------ */
1639 static int stdin_listen = 0;
1640 static char *pcbmenu_path = "gpcb-menu.res";
1642 HID_Attribute ghid_attribute_list[] = {
1644 /* %start-doc options "21 GTK+ GUI Options"
1645 @ftable @code
1646 @item --listen
1647 Listen for actions on stdin.
1648 @end ftable
1649 %end-doc
1651 {"listen", "Listen for actions on stdin",
1652 HID_Boolean, 0, 0, {0, 0, 0}, 0, &stdin_listen},
1653 #define HA_listen 0
1655 /* %start-doc options "21 GTK+ GUI Options"
1656 @ftable @code
1657 @item --bg-image <string>
1658 File name of an image to put into the background of the GUI canvas. The image must
1659 be a color PPM image, in binary (not ASCII) format. It can be any size, and will be
1660 automatically scaled to fit the canvas.
1661 @end ftable
1662 %end-doc
1664 {"bg-image", "Background Image",
1665 HID_String, 0, 0, {0, 0, 0}, 0, &bg_image_file},
1666 #define HA_bg_image 1
1668 /* %start-doc options "21 GTK+ GUI Options"
1669 @ftable @code
1670 @item --pcb-menu <string>
1671 Location of the @file{gpcb-menu.res} file which defines the menu for the GTK+ GUI.
1672 @end ftable
1673 %end-doc
1675 {"pcb-menu", "Location of gpcb-menu.res file",
1676 HID_String, 0, 0, {0, PCBLIBDIR "/gpcb-menu.res", 0}, 0, &pcbmenu_path}
1677 #define HA_pcbmenu 2
1680 REGISTER_ATTRIBUTES (ghid_attribute_list)
1682 HID_Attribute *
1683 ghid_get_export_options (int *n_ret)
1685 *n_ret = sizeof (ghid_attribute_list) / sizeof (HID_Attribute);
1686 return ghid_attribute_list;
1689 /* Create top level window for routines that will need top_window
1690 | before ghid_create_pcb_widgets() is called.
1692 void
1693 ghid_parse_arguments (int *argc, char ***argv)
1695 GtkWidget *window;
1696 gint i;
1697 GdkPixbuf *icon;
1699 /* on windows we need to figure out the installation directory */
1700 #ifdef WIN32
1701 char * tmps;
1702 char * libdir;
1703 tmps = g_win32_get_package_installation_directory(PACKAGE "-" VERSION, NULL);
1704 #define REST_OF_PATH G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S PACKAGE G_DIR_SEPARATOR_S "newlib"
1705 libdir = (char *) malloc(strlen(tmps) +
1706 strlen(REST_OF_PATH) +
1708 sprintf(libdir, "%s%s", tmps, REST_OF_PATH);
1709 free(tmps);
1711 Settings.LibraryTree = libdir;
1713 #undef REST_OF_PATH
1715 #endif
1717 #if defined (DEBUG)
1718 for (i = 0; i < *argc; i++)
1720 printf ("ghid_parse_arguments(): *argv[%d] = \"%s\"\n", i, (*argv)[i]);
1722 #endif
1724 /* Threads aren't used in PCB, but this call would go here.
1726 /* g_thread_init (NULL); */
1728 #if defined (ENABLE_NLS)
1729 /* Do our own setlocale() stufff since we want to override LC_NUMERIC
1731 gtk_set_locale ();
1732 setlocale (LC_NUMERIC, "C"); /* use decimal point instead of comma */
1733 #endif
1736 * Prevent gtk_init() and gtk_init_check() from automatically
1737 * calling setlocale (LC_ALL, "") which would undo LC_NUMERIC if ENABLE_NLS
1738 * We also don't want locale set if no ENABLE_NLS to keep "C" LC_NUMERIC.
1740 gtk_disable_setlocale ();
1742 gtk_init (argc, argv);
1744 gport = &ghid_port;
1745 gport->view.coord_per_px = 300.0;
1746 pixel_slop = 300;
1748 ghid_init_renderer (argc, argv, gport);
1750 ghid_config_files_read (argc, argv);
1752 Settings.AutoPlace = 0;
1753 for (i = 0; i < *argc; i++)
1755 if (strcmp ((*argv)[i], "-auto-place") == 0)
1756 Settings.AutoPlace = 1;
1759 #ifdef ENABLE_NLS
1760 #ifdef LOCALEDIR
1761 bindtextdomain (PACKAGE, LOCALEDIR);
1762 #endif
1763 textdomain (PACKAGE);
1764 bind_textdomain_codeset (PACKAGE, "UTF-8");
1765 #endif /* ENABLE_NLS */
1767 icon = gdk_pixbuf_new_from_xpm_data ((const gchar **) icon_bits);
1768 gtk_window_set_default_icon (icon);
1770 window = gport->top_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1771 gtk_window_set_title (GTK_WINDOW (window), "PCB");
1772 gtk_window_set_default_size(GTK_WINDOW(window),
1773 ghidgui->top_window_width, ghidgui->top_window_height);
1775 if (Settings.AutoPlace)
1776 gtk_window_move (GTK_WINDOW (window), 10, 10);
1778 gtk_widget_show_all (gport->top_window);
1779 ghidgui->creating = TRUE;
1782 void
1783 ghid_do_export (HID_Attr_Val * options)
1785 ghid_create_pcb_widgets ();
1787 /* These are needed to make sure the @layerpick and @layerview menus
1788 * are properly initialized and synchronized with the current PCB.
1790 ghid_layer_buttons_update ();
1791 ghid_main_menu_install_route_style_selector
1792 (GHID_MAIN_MENU (ghidgui->menu_bar),
1793 GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
1795 if (stdin_listen)
1796 ghid_create_listener ();
1798 ghid_notify_gui_is_up ();
1800 gtk_main ();
1801 ghid_config_files_write ();
1805 /*! \brief callback for */
1806 static gboolean
1807 get_layer_visible_cb (int id)
1809 int visible;
1810 layer_process (NULL, NULL, &visible, id);
1811 return visible;
1814 gint
1815 LayersChanged (int argc, char **argv, Coord x, Coord y)
1817 if (!ghidgui || !ghidgui->menu_bar)
1818 return 0;
1820 ghid_config_groups_changed();
1821 ghid_layer_buttons_update ();
1822 ghid_layer_selector_show_layers
1823 (GHID_LAYER_SELECTOR (ghidgui->layer_selector), get_layer_visible_cb);
1825 /* FIXME - if a layer is moved it should retain its color. But layers
1826 | currently can't do that because color info is not saved in the
1827 | pcb file. So this makes a moved layer change its color to reflect
1828 | the way it will be when the pcb is reloaded.
1830 pcb_colors_from_settings (PCB);
1831 return 0;
1834 static const char toggleview_syntax[] =
1835 "ToggleView(1..MAXLAYER)\n"
1836 "ToggleView(layername)\n"
1837 "ToggleView(Silk|Rats|Pins|Vias|Mask|BackSide)";
1839 static const char toggleview_help[] =
1840 "Toggle the visibility of the specified layer or layer group.";
1842 /* %start-doc actions ToggleView
1844 If you pass an integer, that layer is specified by index (the first
1845 layer is @code{1}, etc). If you pass a layer name, that layer is
1846 specified by name. When a layer is specified, the visibility of the
1847 layer group containing that layer is toggled.
1849 If you pass a special layer name, the visibility of those components
1850 (silk, rats, etc) is toggled. Note that if you have a layer named
1851 the same as a special layer, the layer is chosen over the special layer.
1853 %end-doc */
1855 static int
1856 ToggleView (int argc, char **argv, Coord x, Coord y)
1858 int i, l;
1860 #ifdef DEBUG_MENUS
1861 puts ("Starting ToggleView().");
1862 #endif
1864 if (argc == 0)
1866 AFAIL (toggleview);
1868 if (isdigit ((int) argv[0][0]))
1870 l = atoi (argv[0]) - 1;
1872 else if (strcmp (argv[0], "Silk") == 0)
1873 l = LAYER_BUTTON_SILK;
1874 else if (strcmp (argv[0], "Rats") == 0)
1875 l = LAYER_BUTTON_RATS;
1876 else if (strcmp (argv[0], "Pins") == 0)
1877 l = LAYER_BUTTON_PINS;
1878 else if (strcmp (argv[0], "Vias") == 0)
1879 l = LAYER_BUTTON_VIAS;
1880 else if (strcmp (argv[0], "Mask") == 0)
1881 l = LAYER_BUTTON_MASK;
1882 else if (strcmp (argv[0], "BackSide") == 0)
1883 l = LAYER_BUTTON_FARSIDE;
1884 else
1886 l = -1;
1887 for (i = 0; i < max_copper_layer + 2; i++)
1888 if (strcmp (argv[0], PCB->Data->Layer[i].Name) == 0)
1890 l = i;
1891 break;
1893 if (l == -1)
1895 AFAIL (toggleview);
1900 /* Now that we've figured out which toggle button ought to control
1901 * this layer, simply hit the button and let the pre-existing code deal
1903 ghid_layer_selector_toggle_layer
1904 (GHID_LAYER_SELECTOR (ghidgui->layer_selector), l);
1905 return 0;
1908 static const char selectlayer_syntax[] =
1909 "SelectLayer(1..MAXLAYER|Silk|Rats)";
1911 static const char selectlayer_help[] =
1912 "Select which layer is the current layer.";
1914 /* %start-doc actions SelectLayer
1916 The specified layer becomes the currently active layer. It is made
1917 visible if it is not already visible
1919 %end-doc */
1921 static int
1922 SelectLayer (int argc, char **argv, Coord x, Coord y)
1924 int i;
1925 int newl = -1;
1926 if (argc == 0)
1927 AFAIL (selectlayer);
1929 for (i = 0; i < max_copper_layer; ++i)
1930 if (strcasecmp (argv[0], PCB->Data->Layer[i].Name) == 0)
1931 newl = i;
1933 if (strcasecmp (argv[0], "silk") == 0)
1934 newl = LAYER_BUTTON_SILK;
1935 else if (strcasecmp (argv[0], "rats") == 0)
1936 newl = LAYER_BUTTON_RATS;
1937 else if (newl == -1)
1938 newl = atoi (argv[0]) - 1;
1940 #ifdef DEBUG_MENUS
1941 printf ("SelectLayer(): newl = %d\n", newl);
1942 #endif
1944 /* Now that we've figured out which radio button ought to select
1945 * this layer, simply hit the button and let the pre-existing code deal
1947 ghid_layer_selector_select_layer
1948 (GHID_LAYER_SELECTOR (ghidgui->layer_selector), newl);
1950 return 0;
1954 HID_Action gtk_topwindow_action_list[] = {
1955 {"LayersChanged", 0, LayersChanged,
1956 layerschanged_help, layerschanged_syntax},
1957 {"SelectLayer", 0, SelectLayer,
1958 selectlayer_help, selectlayer_syntax},
1959 {"ToggleView", 0, ToggleView,
1960 toggleview_help, toggleview_syntax}
1963 REGISTER_ACTIONS (gtk_topwindow_action_list)
1966 * This function is used to check if a specified hotkey in the menu
1967 * resource file is "special". In this case "special" means that gtk
1968 * assigns a particular meaning to it and the normal menu setup will
1969 * never see these key presses. We capture those and feed them back
1970 * into the menu callbacks. This function is called as new
1971 * accelerators are added when the menus are being built
1973 static void
1974 ghid_check_special_key (const char *accel, GtkAction *action,
1975 const Resource *node)
1977 size_t len;
1978 unsigned int mods;
1979 unsigned int ind;
1981 if (action == NULL || accel == NULL || *accel == '\0')
1982 return ;
1984 #ifdef DEBUG_MENUS
1985 printf ("%s(\"%s\", \"%s\")\n", __FUNCTION__, accel, name);
1986 #endif
1988 mods = 0;
1989 if (strstr (accel, "<alt>") )
1991 mods |= GHID_KEY_ALT;
1993 if (strstr (accel, "<ctrl>") )
1995 mods |= GHID_KEY_CONTROL;
1997 if (strstr (accel, "<shift>") )
1999 mods |= GHID_KEY_SHIFT;
2003 len = strlen (accel);
2005 #define CHECK_KEY(a) ((len >= strlen (a)) && (strcmp (accel + len - strlen (a), (a)) == 0))
2007 ind = 0;
2008 if ( CHECK_KEY ("Tab") )
2010 ind = mods | GHID_KEY_TAB;
2012 else if ( CHECK_KEY ("Up") )
2014 ind = mods | GHID_KEY_UP;
2016 else if ( CHECK_KEY ("Down") )
2018 ind = mods | GHID_KEY_DOWN;
2020 else if ( CHECK_KEY ("Left") )
2022 ind = mods | GHID_KEY_LEFT;
2024 else if ( CHECK_KEY ("Right") )
2026 ind = mods | GHID_KEY_RIGHT;
2029 if (ind > 0)
2031 if (ind >= N_HOTKEY_ACTIONS)
2033 fprintf (stderr, "ERROR: overflow of the ghid_hotkey_actions array. Index = %d\n"
2034 "Please report this.\n", ind);
2035 exit (1);
2038 ghid_hotkey_actions[ind].action = action;
2039 ghid_hotkey_actions[ind].node = node;
2040 #ifdef DEBUG_MENUS
2041 printf ("Adding \"special\" hotkey to ghid_hotkey_actions[%u] :"
2042 " %s (%s)\n", ind, accel, name);
2043 #endif
2047 /*! \brief Finds the gpcb-menu.res file */
2048 char *
2049 get_menu_filename (void)
2051 char *rv = NULL;
2052 char *home_pcbmenu = NULL;
2054 /* homedir is set by the core */
2055 if (homedir)
2057 Message (_("Note: home directory is \"%s\"\n"), homedir);
2058 home_pcbmenu = Concat (homedir, PCB_DIR_SEPARATOR_S, ".pcb",
2059 PCB_DIR_SEPARATOR_S, "gpcb-menu.res", NULL);
2061 else
2062 Message (_("Warning: could not determine home directory\n"));
2064 if (access ("gpcb-menu.res", R_OK) == 0)
2065 rv = strdup ("gpcb-menu.res");
2066 else if (home_pcbmenu != NULL && (access (home_pcbmenu, R_OK) == 0) )
2067 rv = home_pcbmenu;
2068 else if (access (pcbmenu_path, R_OK) == 0)
2069 rv = strdup (pcbmenu_path);
2071 return rv;
2074 static GtkWidget *
2075 ghid_load_menus (void)
2077 char *filename;
2078 const Resource *r = 0, *bir;
2079 const Resource *mr;
2080 GtkWidget *menu_bar = NULL;
2081 int i;
2083 for (i = 0; i < N_HOTKEY_ACTIONS; i++)
2085 ghid_hotkey_actions[i].action = NULL;
2086 ghid_hotkey_actions[i].node = NULL;
2089 bir = resource_parse (0, gpcb_menu_default);
2090 if (!bir)
2092 fprintf (stderr, _("Error: internal menu resource didn't parse\n"));
2093 exit(1);
2096 filename = get_menu_filename ();
2097 if (filename)
2099 Message ("Loading menus from %s\n", filename);
2100 r = resource_parse (filename, 0);
2103 if (!r)
2105 Message ("Using default menus\n");
2106 r = bir;
2108 free (filename);
2110 mr = resource_subres (r, "MainMenu");
2111 if (!mr)
2112 mr = resource_subres (bir, "MainMenu");
2114 if (mr)
2116 menu_bar = ghid_main_menu_new (G_CALLBACK (ghid_menu_cb),
2117 ghid_check_special_key);
2118 ghid_main_menu_add_resource (GHID_MAIN_MENU (menu_bar), mr);
2121 mr = resource_subres (r, "PopupMenus");
2122 if (!mr)
2123 mr = resource_subres (bir, "PopupMenus");
2125 if (mr)
2127 int i;
2128 for (i = 0; i < mr->c; i++)
2129 if (resource_type (mr->v[i]) == 101)
2130 /* This is a named resource which defines a popup menu */
2131 ghid_main_menu_add_popup_resource (GHID_MAIN_MENU (menu_bar),
2132 mr->v[i].name, mr->v[i].subres);
2135 #ifdef DEBUG_MENUS
2136 puts ("Finished loading menus.");
2137 #endif
2139 mr = resource_subres (r, "Mouse");
2140 if (!mr)
2141 mr = resource_subres (bir, "Mouse");
2142 if (mr)
2143 load_mouse_resource (mr);
2145 return menu_bar;
2148 /* ------------------------------------------------------------ */
2150 static const char adjuststyle_syntax[] =
2151 "AdjustStyle()\n";
2153 static const char adjuststyle_help[] =
2154 "Open the window which allows editing of the route styles.";
2156 /* %start-doc actions AdjustStyle
2158 Opens the window which allows editing of the route styles.
2160 %end-doc */
2162 static int
2163 AdjustStyle(int argc, char **argv, Coord x, Coord y)
2165 if (argc > 1)
2166 AFAIL (adjuststyle);
2168 ghid_route_style_selector_edit_dialog
2169 (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
2170 return 0;
2173 /* ------------------------------------------------------------ */
2175 static const char editlayergroups_syntax[] =
2176 "EditLayerGroups()\n";
2178 static const char editlayergroups_help[] =
2179 "Open the preferences window which allows editing of the layer groups.";
2181 /* %start-doc actions EditLayerGroups
2183 Opens the preferences window which is where the layer groups
2184 are edited. This action is primarily provides to provide menu
2185 resource compatibility with the lesstif HID.
2187 %end-doc */
2189 static int
2190 EditLayerGroups(int argc, char **argv, Coord x, Coord y)
2193 if (argc != 0)
2194 AFAIL (editlayergroups);
2196 hid_actionl ("DoWindows", "Preferences", NULL);
2198 return 0;
2201 /* ------------------------------------------------------------ */
2203 HID_Action ghid_menu_action_list[] = {
2204 {"AdjustStyle", 0, AdjustStyle, adjuststyle_help, adjuststyle_syntax},
2205 {"EditLayerGroups", 0, EditLayerGroups, editlayergroups_help, editlayergroups_syntax}
2208 REGISTER_ACTIONS (ghid_menu_action_list)