Introduce POLYGONHOLE_MODE for creating holes in polygons
[geda-pcb/gde.git] / src / hid / gtk / gui-top-window.c
blob4c00c133a9a4bf6655e4949e62758fc7c57d21ac
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996 Thomas Nau
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 /* #define DEBUG_MENUS */
27 #ifdef DAN_FIXME
28 TODO:
30 - figure out when we need to call this:
31 ghid_set_status_line_label ();
32 Everytime?
34 - the old quit callback had:
36 ghid_config_files_write ();
37 hid_action ("Quit");
39 - what about stuff like this:
41 /* Set to ! because ActionDisplay toggles it */
42 Settings.DrawGrid = !gtk_toggle_action_get_active (action);
43 ghidgui->config_modified = TRUE;
44 hid_actionl ("Display", "Grid", "", NULL);
45 ghid_set_status_line_label ();
48 I NEED TO DO THE STATUS LINE THING. for example shift-alt-v to change the
49 via size. NOte the status line label does not get updated properly until
50 a zoom in/out.
52 - do not forget I can use
53 if (!ghidgui->toggle_holdoff)
55 #endif
57 /* This file was originally written by Bill Wilson for the PCB Gtk
58 * port. It was later heavily modified by Dan McMahill to provide
59 * user customized menus.
63 /* gui-top-window.c
64 | This handles creation of the top level window and all its widgets.
65 | events for the Output.drawing_area widget are handled in a separate
66 | file gui-output-events.c
68 | Some caveats with menu shorcut keys: Some keys are trapped out by Gtk
69 | and can't be used as shortcuts (eg. '|', TAB, etc). For these cases
70 | we have our own shortcut table and capture the keys and send the events
71 | there in ghid_port_key_press_cb().
75 #ifdef HAVE_CONFIG_H
76 #include "config.h"
77 #endif
79 #include <unistd.h>
81 #ifdef HAVE_LOCALE_H
82 #include <locale.h>
83 #endif
85 #include "gtkhid.h"
86 #include "gui.h"
87 #include "hid.h"
88 #include "../hidint.h"
89 #include "hid/common/hid_resource.h"
91 #include "action.h"
92 #include "autoplace.h"
93 #include "autoroute.h"
94 #include "buffer.h"
95 #include "change.h"
96 #include "command.h"
97 #include "copy.h"
98 #include "create.h"
99 #include "crosshair.h"
100 #include "draw.h"
101 #include "error.h"
102 #include "file.h"
103 #include "find.h"
104 #include "gpcb-menu.h"
105 #include "insert.h"
106 #include "line.h"
107 #include "mymem.h"
108 #include "misc.h"
109 #include "move.h"
110 #include "polygon.h"
111 #include "rats.h"
112 #include "remove.h"
113 #include "report.h"
114 #include "resource.h"
115 #include "rotate.h"
116 #include "rubberband.h"
117 #include "search.h"
118 #include "select.h"
119 #include "set.h"
120 #include "undo.h"
121 #include "vendor.h"
123 #include "gui-icons-mode-buttons.data"
124 #include "gui-icons-misc.data"
126 #ifdef HAVE_LIBDMALLOC
127 #include <dmalloc.h>
128 #endif
130 RCSID ("$Id$");
132 /* ---------------------------------------------------------------------------
133 * local types
137 typedef enum {GHID_FLAG_ACTIVE, GHID_FLAG_CHECKED, GHID_FLAG_VISIBLE} MenuFlagType;
139 /* Used by the menuitems that are toggle actions */
140 typedef struct
142 const char *actionname;
143 const char *flagname;
144 MenuFlagType flagtype;
145 int oldval;
146 char *xres;
147 } ToggleFlagType;
149 /* Used by the route style buttons and menu */
150 typedef struct
152 GtkWidget *button;
153 RouteStyleType route_style;
154 gboolean shown; /* For temp buttons */
156 RouteStyleButton;
158 /* Used by the layer buttons */
159 typedef struct
161 GtkWidget *radio_select_button,
162 *layer_enable_button, *layer_enable_ebox, *label;
163 gchar *text;
164 gint index;
166 LayerButtonSet;
169 /* ---------------------------------------------------------------------------
170 * local macros
173 /* ---------------------------------------------------------------------------
174 * local prototypes
178 #define N_ROUTE_STYLES (NUM_STYLES + 3)
180 static void ghid_load_menus (void);
181 static void ghid_ui_info_append (const gchar *);
182 static void ghid_ui_info_indent (int);
184 static gchar * new_ui_info;
185 static size_t new_ui_info_sz = 0;
187 /* the array of actions for "normal" menuitems */
188 static GtkActionEntry *new_entries = NULL;
189 static gint menuitem_cnt = 0;
191 /* the array of actions for "toggle" menuitems */
192 static GtkToggleActionEntry *new_toggle_entries = NULL;
193 static gint tmenuitem_cnt = 0;
195 static Resource **action_resources = NULL;
196 static Resource **toggle_action_resources = NULL;
198 /* actions for the @layerview menuitems */
199 static GtkToggleActionEntry layerview_toggle_entries[N_LAYER_BUTTONS];
200 static Resource *layerview_resources[N_LAYER_BUTTONS];
202 /* actions for the @layerpick menuitems */
203 static GtkToggleActionEntry layerpick_toggle_entries[N_LAYER_BUTTONS];
204 static Resource *layerpick_resources[N_LAYER_BUTTONS];
206 /* actions for the @routestyles menuitems */
207 static GtkToggleActionEntry routestyle_toggle_entries[N_ROUTE_STYLES];
208 static Resource *routestyle_resources[N_ROUTE_STYLES];
210 #define MENUITEM "MenuItem"
211 #define TMENUITEM "TMenuItem"
212 #define LAYERPICK "LayerPick"
213 #define LAYERVIEW "LayerView"
214 #define ROUTESTYLE "RouteStyle"
217 static ToggleFlagType *tflags = 0;
218 static int n_tflags = 0;
219 static int max_tflags = 0;
221 extern HID ghid_hid;
223 GhidGui _ghidgui, *ghidgui = NULL;
225 GHidPort ghid_port, *gport;
227 static GdkColor WhitePixel, BlackPixel;
229 static gchar *bg_image_file;
231 static char *ghid_hotkey_actions[256];
234 /* ------------------------------------------------------------------
235 * Route style buttons
238 /* Make 3 extra route style radio buttons. 2 for the extra Temp route
239 * styles, and the 3rd is an always invisible button selected when the
240 * route style settings in use don't match any defined route style (the
241 * user can hit 'l', 'v', etc keys to change the settings without selecting
242 * a new defined style.
245 static RouteStyleButton route_style_button[N_ROUTE_STYLES];
246 static gint route_style_index;
248 static GtkWidget *route_style_edit_button;
250 static const char *
251 ghid_check_unique_accel (const char *accelerator)
253 static int n_list = 0;
254 static char **accel_list;
255 static int amax = 0;
256 int i;
257 const char * a = accelerator;
259 if (accelerator == NULL)
260 return NULL;
262 if (strlen (accelerator) == 0)
263 return accelerator;
265 if (amax >= n_list)
267 n_list += 128;
268 if ( (accel_list = realloc (accel_list, n_list * sizeof (char *))) == NULL)
270 fprintf (stderr, "%s(): realloc failed\n", __FUNCTION__);
271 exit (1);
275 for (i = 0; i < amax ; i++)
277 if (strcmp (accel_list[i], accelerator) == 0)
279 Message (_("Duplicate accelerator found: \"%s\"\n"
280 "The second occurance will be dropped\n"),
281 accelerator);
282 a = NULL;
283 break;
286 accel_list[amax] = strdup (accelerator);
287 amax++;
289 return a;
293 /* ------------------------------------------------------------------
294 * note_toggle_flag()
297 static void
298 note_toggle_flag (const char *actionname, MenuFlagType type, char *name)
301 #ifdef DEBUG_MENUS
302 printf ("note_toggle_flag(\"%s\", %d, \"%s\")\n", actionname, type, name);
303 #endif
305 if (n_tflags >= max_tflags)
307 max_tflags += 20;
308 tflags =
309 MyRealloc (tflags, max_tflags * sizeof (ToggleFlagType),
310 __FUNCTION__);
312 tflags[n_tflags].actionname = strdup (actionname);
313 tflags[n_tflags].flagname = name;
314 tflags[n_tflags].flagtype = type;
315 tflags[n_tflags].oldval = -1;
316 tflags[n_tflags].xres = "none";
317 n_tflags++;
321 void
322 ghid_update_toggle_flags ()
324 int i;
326 GtkAction *a;
327 gboolean old_holdoff;
328 gboolean active;
329 char tmpnm[40];
330 GValue setfalse = { 0 };
331 GValue settrue = { 0 };
332 GValue setlabel = { 0 };
334 g_value_init (&setfalse, G_TYPE_BOOLEAN);
335 g_value_init (&settrue, G_TYPE_BOOLEAN);
336 g_value_set_boolean (&setfalse, FALSE);
337 g_value_set_boolean (&settrue, TRUE);
338 g_value_init (&setlabel, G_TYPE_STRING);
340 /* mask the callbacks */
341 old_holdoff = ghidgui->toggle_holdoff;
342 ghidgui->toggle_holdoff = TRUE;
344 for (i = 0; i < n_tflags; i++)
346 switch (tflags[i].flagtype)
348 case GHID_FLAG_ACTIVE:
350 int v = hid_get_flag (tflags[i].flagname);
351 a = gtk_action_group_get_action (ghidgui->main_actions, tflags[i].actionname);
352 g_object_set_property (G_OBJECT (a), "sensitive", v? &settrue : &setfalse);
353 tflags[i].oldval = v;
355 break;
357 case GHID_FLAG_CHECKED:
359 int v = hid_get_flag (tflags[i].flagname);
360 a = gtk_action_group_get_action (ghidgui->main_actions, tflags[i].actionname);
361 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (a), v? TRUE : FALSE);
362 tflags[i].oldval = v;
364 break;
366 default:
367 printf ("Skipping flagtype %d\n", tflags[i].flagtype);
368 break;
373 /* FIXME -- this probably needs to go somewhere else */
374 #ifdef notdef
375 for (i = 0; i < N_LAYER_BUTTONS; i++)
377 sprintf (tmpnm, "%s%d", LAYERVIEW, i);
378 a = gtk_action_group_get_action (ghidgui->main_actions, tmpnm);
379 if (a != NULL)
381 g_object_set_property (G_OBJECT (a), "visible", (i >= max_layer && i < MAX_LAYER) ? &setfalse : &settrue);
385 #endif
387 for (i = 0; i < N_ROUTE_STYLES; i++)
389 sprintf (tmpnm, "%s%d", ROUTESTYLE, i);
390 a = gtk_action_group_get_action (ghidgui->main_actions, tmpnm);
391 if (i >= NUM_STYLES)
393 g_object_set_property (G_OBJECT (a), "visible", &setfalse);
396 /* Update the toggle states */
397 active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (route_style_button[i].button));
398 #ifdef DEBUG_MENUS
399 printf ("ghid_update_toggle_flags(): route style %d, value is %d\n", i, active);
400 #endif
401 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (a), active);
405 g_value_unset (&setfalse);
406 g_value_unset (&settrue);
407 g_value_unset (&setlabel);
408 ghidgui->toggle_holdoff = old_holdoff;
412 #define N_GRID_SETTINGS 11
414 #define MM_TO_PCB(mm) ((mm) * 100000 / 25.4)
416 static gdouble grid_mil_values[N_GRID_SETTINGS] = {
417 10.0,
418 20.0,
419 50.0,
420 100.0,
421 200.0,
422 500.0,
423 1000.0,
424 2000.0,
425 2500.0,
426 5000.0,
427 10000.0
430 static gdouble grid_mm_values[N_GRID_SETTINGS] = {
431 MM_TO_PCB (0.002),
432 MM_TO_PCB (0.005),
433 MM_TO_PCB (0.01),
434 MM_TO_PCB (0.02),
435 MM_TO_PCB (0.05),
436 MM_TO_PCB (0.1),
437 MM_TO_PCB (0.2),
438 MM_TO_PCB (0.25),
439 MM_TO_PCB (0.5),
440 MM_TO_PCB (1.0),
441 MM_TO_PCB (2.0)
444 /* When the user toggles grid units mil<->mm, call this to get an
445 | index into the grid values table of the current grid setting. Then a
446 | grid in the new units may be selected that is closest to what we had.
448 | May want this call to fail if user has altered grid with 'g' key
449 | and so current grid does not match any of the presets. In that
450 | case we want no item in the grid setting radio group to get set.
452 static gint
453 get_grid_value_index (gboolean allow_fail)
455 gdouble *value;
456 gint i;
458 value = Settings.grid_units_mm ? &grid_mm_values[0] : &grid_mil_values[0];
459 for (i = 0; i < N_GRID_SETTINGS; ++i, ++value)
460 if (PCB->Grid < *value + 1.0 && PCB->Grid > *value - 1.0)
461 break;
462 if (i >= N_GRID_SETTINGS)
463 i = allow_fail ? -1 : N_GRID_SETTINGS - 1;
465 return i;
468 static void
469 h_adjustment_changed_cb (GtkAdjustment * adj, GhidGui * g)
471 gdouble xval, yval;
473 if (g->adjustment_changed_holdoff)
474 return;
475 xval = gtk_adjustment_get_value (adj);
476 yval = gtk_adjustment_get_value (GTK_ADJUSTMENT (ghidgui->v_adjustment));
477 ghid_port_ranges_changed ();
480 static void
481 v_adjustment_changed_cb (GtkAdjustment * adj, GhidGui * g)
483 gdouble xval, yval;
485 if (g->adjustment_changed_holdoff)
486 return;
487 yval = gtk_adjustment_get_value (adj);
488 xval = gtk_adjustment_get_value (GTK_ADJUSTMENT (ghidgui->h_adjustment));
489 ghid_port_ranges_changed ();
492 /* Save size of top window changes so PCB can restart at its size at exit.
494 static gint
495 top_window_configure_event_cb (GtkWidget * widget, GdkEventConfigure * ev,
496 GHidPort * port)
498 gboolean new_w, new_h;
500 new_w = (ghidgui->top_window_width != widget->allocation.width);
501 new_h = (ghidgui->top_window_height != widget->allocation.height);
503 ghidgui->top_window_width = widget->allocation.width;
504 ghidgui->top_window_height = widget->allocation.height;
506 if (new_w || new_h)
507 ghidgui->config_modified = TRUE;
509 return FALSE;
514 * This is the main menu callback function. The callback looks at
515 * the gtk action name to figure out which menuitem was chosen. Then
516 * it looks up in a table to find the pcb actions which should be
517 * executed. All menus go through this callback. The tables of
518 * actions are loaded from the menu resource file at startup.
520 * In addition, all hotkeys go through the menus which means they go
521 * through here.
524 static void
525 ghid_menu_cb (GtkAction * action, gpointer data)
527 const gchar * name;
528 int id = 0;
529 int vi;
530 Resource *node = NULL;
531 static int in_cb = 0;
532 gboolean old_holdoff;
534 /* If we don't do this then we can end up in loops where changing
535 * the state of the toggle actions triggers the callbacks and
536 * the call back updates the state of the actions.
538 if (in_cb)
539 return;
540 else
541 in_cb = 1;
544 * Normally this callback is triggered by the menus in which case
545 * action will be the gtk action which was triggered. In the case
546 * of the "special" hotkeys we will call this callback directly and
547 * pass in the name of the menu that it corresponds to in via the
548 * data argument
550 if (action != NULL)
552 name = gtk_action_get_name (action);
554 else
556 name = (char *) data;
557 #ifdef DEBUG_MENUS
558 printf ("ghid_menu_cb(): name = \"%s\"\n", UNKNOWN (name));
559 #endif
562 if (name == NULL)
564 fprintf (stderr, "%s(%p, %p): name == NULL\n",
565 __FUNCTION__, action, data);
566 in_cb = 0;
567 return;
570 if ( strncmp (name, MENUITEM, strlen (MENUITEM)) == 0)
572 /* This is a "normal" menuitem as opposed to a toggle menuitem
574 id = atoi (name + strlen (MENUITEM));
575 node = action_resources[id];
577 else if ( strncmp (name, TMENUITEM, strlen (TMENUITEM)) == 0)
579 /* This is a "toggle" menuitem */
580 id = atoi (name + strlen (TMENUITEM));
582 /* toggle_holdoff lets us update the state of the menus without
583 * actually triggering all the callbacks
585 if (ghidgui->toggle_holdoff == TRUE)
586 node = NULL;
587 else
588 node = toggle_action_resources[id];
590 else if ( strncmp (name, LAYERPICK, strlen (LAYERPICK)) == 0)
592 id = atoi (name + strlen (LAYERPICK));
594 if (ghidgui->toggle_holdoff == TRUE)
595 node = NULL;
596 else
597 node = layerpick_resources[id];
599 else if ( strncmp (name, LAYERVIEW, strlen (LAYERVIEW)) == 0)
601 id = atoi (name + strlen (LAYERVIEW));
603 if (ghidgui->toggle_holdoff == TRUE)
604 node = NULL;
605 else
606 node = layerview_resources[id];
608 else if ( strncmp (name, ROUTESTYLE, strlen (ROUTESTYLE)) == 0)
610 id = atoi (name + strlen (ROUTESTYLE));
611 if (ghidgui->toggle_holdoff != TRUE)
612 ghid_route_style_button_set_active (id);
613 node = NULL;
615 else
617 fprintf (stderr, "ERROR: ghid_menu_cb(): name = \"%s\" is unknown\n", name);
621 #ifdef DEBUG_MENUS
622 printf ("ghid_menu_cb(): name = \"%s\", id = %d\n", name, id);
623 #endif
625 /* Now we should have a pointer to the actions to execute */
626 if (node != NULL)
628 for (vi = 1; vi < node->c; vi++)
629 if (resource_type (node->v[vi]) == 10)
631 #ifdef DEBUG_MENUS
632 printf (" %s\n", node->v[vi].value);
633 #endif
634 hid_parse_actions (node->v[vi].value);
637 else {
638 #ifdef DEBUG_MENUS
639 printf (" NOOP\n");
640 #endif
645 * Now mask off any callbacks and update the state of any toggle
646 * menuitems. This is where we do things like sync the layer or
647 * tool checks marks in the menus with the layer or tool buttons
649 old_holdoff = ghidgui->toggle_holdoff;
650 ghidgui->toggle_holdoff = TRUE;
651 ghid_update_toggle_flags ();
652 ghidgui->toggle_holdoff = old_holdoff;
654 in_cb = 0;
657 * and finally, make any changes show up in the status line and the
658 * screen
660 if (ghidgui->toggle_holdoff == FALSE)
662 HideCrosshair (TRUE);
663 AdjustAttachedObjects ();
664 ghid_invalidate_all ();
665 RestoreCrosshair (TRUE);
666 ghid_screen_update ();
667 ghid_set_status_line_label ();
668 #ifdef FIXME
669 g_idle_add (ghid_idle_cb, NULL);
670 #endif
675 void ghid_hotkey_cb (int which)
677 #ifdef DEBUG_MENUS
678 printf ("%s(%d) -> \"%s\"\n", __FUNCTION__,
679 which, UNKNOWN (ghid_hotkey_actions[which]));
680 #endif
681 if (ghid_hotkey_actions[which] != NULL)
682 ghid_menu_cb (NULL, ghid_hotkey_actions[which]);
686 /* ============== ViewMenu callbacks =============== */
689 /* Do grid units handling common to a grid units change from the menu or
690 | the grid units button.
692 static void
693 handle_grid_units_change (gboolean active)
695 gchar *grid;
696 gint i;
698 i = get_grid_value_index (FALSE);
699 Settings.grid_units_mm = active;
700 PCB->Grid = Settings.grid_units_mm ? grid_mm_values[i] : grid_mil_values[i];
702 ghid_grid_setting_update_menu_actions ();
704 grid = g_strdup_printf ("%f", PCB->Grid);
705 hid_actionl ("SetValue", "Grid", grid, "", NULL);
706 g_free (grid);
708 ghid_config_handle_units_changed ();
710 ghid_set_status_line_label ();
713 static void
714 radio_grid_mil_setting_cb (GtkAction * action, GtkRadioAction * current)
716 gdouble value;
717 gchar *grid;
718 gint index;
720 printf ("radio_grid_mil_setting_cb()\n");
721 if (ghidgui->toggle_holdoff)
722 return;
723 index = gtk_radio_action_get_current_value (current);
724 value = grid_mil_values[index];
725 grid = g_strdup_printf ("%f", value);
726 hid_actionl ("SetValue", "Grid", grid, "", NULL);
727 g_free (grid);
728 ghid_set_status_line_label ();
731 static void
732 radio_grid_mm_setting_cb (GtkAction * action, GtkRadioAction * current)
734 gdouble value;
735 gchar *grid;
736 gint index;
738 printf ("radio_grid_mm_setting_cb()\n");
739 if (ghidgui->toggle_holdoff)
740 return;
741 index = gtk_radio_action_get_current_value (current);
742 value = grid_mm_values[index];
743 grid = g_strdup_printf ("%f", value);
744 hid_actionl ("SetValue", "Grid", grid, "", NULL);
745 g_free (grid);
746 ghid_set_status_line_label ();
750 static GtkRadioActionEntry radio_grid_mil_setting_entries[] = {
751 /* name, stock_id, label, accelerator, tooltip, value */
752 {"grid-user", NULL, "user value", NULL, NULL, 0},
753 {"grid0", NULL, "0.1 mil", NULL, NULL, 0},
754 {"grid1", NULL, "0.2 mil", NULL, NULL, 1},
755 {"grid2", NULL, "0.5 mil", NULL, NULL, 2},
756 {"grid3", NULL, "1 mil", NULL, NULL, 3},
757 {"grid4", NULL, "2 mil", NULL, NULL, 4},
758 {"grid5", NULL, "5 mil", NULL, NULL, 5},
759 {"grid6", NULL, "10 mil", NULL, NULL, 6},
760 {"grid7", NULL, "20 mil", NULL, NULL, 7},
761 {"grid8", NULL, "25 mil", NULL, NULL, 8},
762 {"grid9", NULL, "50 mil", NULL, NULL, 9},
763 {"grid10", NULL, "100 mil", NULL, NULL, 10}
766 static gint n_radio_grid_mil_setting_entries
767 = G_N_ELEMENTS (radio_grid_mil_setting_entries);
770 static GtkRadioActionEntry radio_grid_mm_setting_entries[] = {
771 /* name, stock_id, label, accelerator, tooltip, value */
772 {"grid-user", NULL, "user value", NULL, NULL, 0},
773 {"grid0", NULL, "0.002 mm", NULL, NULL, 0},
774 {"grid1", NULL, "0.005 mm", NULL, NULL, 1},
775 {"grid2", NULL, "0.01 mm", NULL, NULL, 2},
776 {"grid3", NULL, "0.02 mm", NULL, NULL, 3},
777 {"grid4", NULL, "0.05 mm", NULL, NULL, 4},
778 {"grid5", NULL, "0.1 mm", NULL, NULL, 5},
779 {"grid6", NULL, "0.2 mm", NULL, NULL, 6},
780 {"grid7", NULL, "0.25 mm", NULL, NULL, 7},
781 {"grid8", NULL, "0.5 mm", NULL, NULL, 8},
782 {"grid9", NULL, "1 mm", NULL, NULL, 9},
783 {"grid10", NULL, "2 mm", NULL, NULL, 10},
786 static gint n_radio_grid_mm_setting_entries
787 = G_N_ELEMENTS (radio_grid_mm_setting_entries);
791 /* Grid setting labels must also match user and new layout unit changes.
793 void
794 ghid_grid_setting_update_menu_actions (void)
796 GtkAction *action;
797 gint i;
799 if (ghidgui->grid_actions)
801 /* Remove the existing radio grid actions from the menu.
803 gtk_ui_manager_remove_action_group (ghidgui->ui_manager,
804 ghidgui->grid_actions);
805 g_object_unref (ghidgui->grid_actions);
808 /* And add back actions appropriate for mil or mm grid settings.
810 ghidgui->grid_actions = gtk_action_group_new ("GridActions");
811 gtk_action_group_set_translation_domain (ghidgui->grid_actions, NULL);
812 gtk_ui_manager_insert_action_group (ghidgui->ui_manager,
813 ghidgui->grid_actions, 0);
815 /* Get the index of the radio button to set depending on current
816 | PCB Grid value. But if user hits 'g' key and no grid index matches,
817 | 'i' will be -1 and no button will be set active. At least Gtk docs
818 | say so, but I see different.
820 i = get_grid_value_index (TRUE);
822 if (Settings.grid_units_mm)
823 gtk_action_group_add_radio_actions (ghidgui->grid_actions,
824 radio_grid_mm_setting_entries,
825 n_radio_grid_mm_setting_entries,
827 G_CALLBACK (radio_grid_mm_setting_cb),
828 NULL);
829 else
830 gtk_action_group_add_radio_actions (ghidgui->grid_actions,
831 radio_grid_mil_setting_entries,
832 n_radio_grid_mil_setting_entries,
834 G_CALLBACK
835 (radio_grid_mil_setting_cb), NULL);
836 action = gtk_action_group_get_action (ghidgui->grid_actions, "grid-user");
837 if (action)
838 g_object_set (action, "sensitive", FALSE, NULL);
843 void
844 ghid_set_menu_toggle_button (GtkActionGroup * ag, gchar * name,
845 gboolean state)
847 GtkAction *action;
848 gboolean old_holdoff;
850 old_holdoff = ghidgui->toggle_holdoff;
851 ghidgui->toggle_holdoff = TRUE;
852 action = gtk_action_group_get_action (ag, name);
853 if (action)
854 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), state);
855 ghidgui->toggle_holdoff = old_holdoff;
858 /* Sync toggle states that were saved with the layout and notify the
859 | config code to update Settings values it manages.
861 void
862 ghid_sync_with_new_layout (void)
864 gboolean old_holdoff;
866 /* Just want to update the state of the menus without calling the
867 | action functions at this time because causing a toggle action can
868 | undo the initial condition set we want here.
870 old_holdoff = ghidgui->toggle_holdoff;
871 ghidgui->toggle_holdoff = TRUE;
873 /* FIXME - need toggle_holdoff? Need other calls to sync here? */
875 ghidgui->toggle_holdoff = old_holdoff;
877 pcb_use_route_style (&PCB->RouteStyle[0]);
879 ghid_route_style_button_set_active (0);
880 ghid_config_handle_units_changed ();
882 ghid_set_status_line_label ();
886 * Sync toggle states in the menus at startup to Settings values loaded
887 * in the config.
889 void
890 ghid_init_toggle_states (void)
892 GtkAction *action;
893 gboolean old_holdoff;
895 /* Just want to update the state of the menus without calling the
896 | action functions at this time because causing a toggle action can
897 | undo the initial condition set we want here.
899 old_holdoff = ghidgui->toggle_holdoff;
900 ghidgui->toggle_holdoff = TRUE;
902 action =
903 gtk_action_group_get_action (ghidgui->main_actions, "ToggleDrawGrid");
904 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
905 Settings.DrawGrid);
907 action = gtk_action_group_get_action (ghidgui->main_actions,
908 "ToggleGridUnitsMm");
909 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
910 Settings.grid_units_mm);
912 action = gtk_action_group_get_action (ghidgui->main_actions,
913 "TogglePinoutShowsNumber");
914 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
915 Settings.ShowNumber);
917 action = gtk_action_group_get_action (ghidgui->main_actions,
918 "Toggle45degree");
919 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
920 Settings.AllDirectionLines);
922 action = gtk_action_group_get_action (ghidgui->main_actions,
923 "ToggleRubberBand");
924 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
925 Settings.RubberBandMode);
927 action = gtk_action_group_get_action (ghidgui->main_actions,
928 "ToggleStartDirection");
929 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
930 Settings.SwapStartDirection);
932 action = gtk_action_group_get_action (ghidgui->main_actions,
933 "ToggleUniqueNames");
934 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
935 Settings.UniqueNames);
937 action = gtk_action_group_get_action (ghidgui->main_actions,
938 "ToggleSnapPin");
939 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), Settings.SnapPin);
941 action = gtk_action_group_get_action (ghidgui->main_actions,
942 "ToggleClearLine");
943 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
944 Settings.ClearLine);
946 action = gtk_action_group_get_action (ghidgui->main_actions,
947 "ToggleOrthogonalMoves");
948 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
949 Settings.OrthogonalMoves);
951 action = gtk_action_group_get_action (ghidgui->main_actions,
952 "ToggleLiveRoute");
953 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
954 Settings.liveRouting);
956 action = gtk_action_group_get_action (ghidgui->main_actions,
957 "ToggleShowDRC");
958 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), Settings.ShowDRC);
960 action = gtk_action_group_get_action (ghidgui->main_actions,
961 "ToggleAutoDrC");
962 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), Settings.AutoDRC);
964 ghidgui->toggle_holdoff = old_holdoff;
965 ghid_set_status_line_label ();
968 /* ---------------------------------------------------------------------------
970 * layer_process()
972 * Takes the index into the layers and produces the text string for
973 * the layer and if the layer is currently visible or not. This is
974 * used by a couple of functions.
977 static void
978 layer_process (gchar **color_string, char **text, int *set, int i)
980 int tmp;
981 char *tmps;
982 gchar *tmpc;
984 /* cheap hack to let users pass in NULL for either text or set if
985 * they don't care about the result
988 if (color_string == NULL)
989 color_string = &tmpc;
991 if (text == NULL)
992 text = &tmps;
994 if (set == NULL)
995 set = &tmp;
997 switch (i)
999 case LAYER_BUTTON_SILK:
1000 *color_string = PCB->ElementColor;
1001 *text = _( "silk");
1002 *set = PCB->ElementOn;
1003 break;
1004 case LAYER_BUTTON_RATS:
1005 *color_string = PCB->RatColor;
1006 *text = _( "rat lines");
1007 *set = PCB->RatOn;
1008 break;
1009 case LAYER_BUTTON_PINS:
1010 *color_string = PCB->PinColor;
1011 *text = _( "pins/pads");
1012 *set = PCB->PinOn;
1013 break;
1014 case LAYER_BUTTON_VIAS:
1015 *color_string = PCB->ViaColor;
1016 *text = _( "vias");
1017 *set = PCB->ViaOn;
1018 break;
1019 case LAYER_BUTTON_FARSIDE:
1020 *color_string = PCB->InvisibleObjectsColor;
1021 *text = _( "far side");
1022 *set = PCB->InvisibleObjectsOn;
1023 break;
1024 case LAYER_BUTTON_MASK:
1025 *color_string = PCB->MaskColor;
1026 *text = _( "solder mask");
1027 *set = TEST_FLAG (SHOWMASKFLAG, PCB);
1028 break;
1029 default: /* layers */
1030 *color_string = PCB->Data->Layer[i].Color;
1031 *text = UNKNOWN (PCB->Data->Layer[i].Name);
1032 *set = PCB->Data->Layer[i].On;
1033 break;
1038 * The intial loading of all actions at startup.
1040 static void
1041 ghid_make_programmed_menu_actions ()
1043 int i;
1044 gchar * text;
1046 Resource *ar;
1047 char av[64];
1049 for (i = 0; i < N_LAYER_BUTTONS; i++)
1051 layer_process (NULL, &text, NULL, i);
1052 #ifdef DEBUG_MENUS
1053 printf ("ghid_make_programmed_menu_actions(): Added #%2d \"%s\". max_layer = %d, MAX_LAYER = %d\n", i, text, max_layer, MAX_LAYER);
1054 #endif
1055 /* name, stock_id, label, accelerator, tooltip, callback */
1056 layerview_toggle_entries[i].name = g_strdup_printf ("%s%d", LAYERVIEW, i);
1057 layerview_toggle_entries[i].stock_id = NULL;
1058 layerview_toggle_entries[i].label = g_strdup (text);
1059 layerview_toggle_entries[i].accelerator = NULL;
1060 layerview_toggle_entries[i].tooltip = NULL;
1061 layerview_toggle_entries[i].callback = G_CALLBACK (ghid_menu_cb);
1062 layerview_toggle_entries[i].is_active = FALSE;
1064 ar = resource_create (0);
1065 sprintf (av, "ToggleView(%d)", i + 1);
1066 resource_add_val (ar, 0, strdup (av), 0);
1067 resource_add_val (ar, 0, strdup (av), 0);
1068 ar->flags |= FLAG_V;
1069 layerview_resources[i] = ar;
1071 /* name, stock_id, label, accelerator, tooltip, callback */
1072 layerpick_toggle_entries[i].name = g_strdup_printf ("%s%d", LAYERPICK, i);
1073 layerpick_toggle_entries[i].stock_id = NULL;
1074 layerpick_toggle_entries[i].label = g_strdup (text);
1075 layerpick_toggle_entries[i].accelerator = NULL;
1076 layerpick_toggle_entries[i].tooltip = NULL;
1077 layerpick_toggle_entries[i].callback = G_CALLBACK (ghid_menu_cb);
1078 layerpick_toggle_entries[i].is_active = FALSE;
1080 ar = resource_create (0);
1081 switch (i)
1083 case LAYER_BUTTON_SILK:
1084 sprintf (av, "SelectLayer(Silk) LayersChanged()");
1085 break;
1086 case LAYER_BUTTON_RATS:
1087 sprintf (av, "SelectLayer(Rats) LayersChanged()");
1088 break;
1089 default:
1090 if (i <= 8)
1091 layerpick_toggle_entries[i].accelerator =
1092 g_strdup_printf ("<Key>%d", i + 1);
1094 sprintf (av, "SelectLayer(%d) LayersChanged()",
1095 i + 1);
1097 break;
1099 resource_add_val (ar, 0, strdup (av), 0);
1100 resource_add_val (ar, 0, strdup (av), 0);
1101 ar->flags |= FLAG_V;
1102 layerpick_resources[i] = ar;
1105 for (i = 0; i < N_ROUTE_STYLES; i++)
1107 routestyle_toggle_entries[i].name = g_strdup_printf ("%s%d", ROUTESTYLE, i);
1108 routestyle_toggle_entries[i].stock_id = NULL;
1109 if (i < NUM_STYLES && PCB)
1111 routestyle_toggle_entries[i].label = g_strdup ( (PCB->RouteStyle)[i].Name);
1113 else
1115 routestyle_toggle_entries[i].label = g_strdup (routestyle_toggle_entries[i].name);
1117 routestyle_toggle_entries[i].accelerator = NULL;
1118 routestyle_toggle_entries[i].tooltip = NULL;
1119 routestyle_toggle_entries[i].callback = G_CALLBACK (ghid_menu_cb);
1120 routestyle_toggle_entries[i].is_active = FALSE;
1122 ar = resource_create (0);
1123 sprintf (av, "RouteStyle(%d)", i + 1);
1124 resource_add_val (ar, 0, strdup (av), 0);
1125 resource_add_val (ar, 0, strdup (av), 0);
1126 ar->flags |= FLAG_V;
1127 routestyle_resources[i] = ar;
1129 // FIXME
1130 //sprintf (av, "current_style,%d", i + 1);
1131 //note_toggle_flag (routestyle_toggle_entries[i].name, strdup (av));
1136 static void
1137 make_menu_actions (GtkActionGroup * actions, GHidPort * port)
1139 gtk_action_group_add_actions (actions, new_entries, menuitem_cnt, port);
1141 gtk_action_group_add_toggle_actions (actions, new_toggle_entries,
1142 tmenuitem_cnt, port);
1144 ghid_make_programmed_menu_actions ();
1146 gtk_action_group_add_toggle_actions (actions,
1147 layerpick_toggle_entries,
1148 N_LAYER_BUTTONS, port);
1150 gtk_action_group_add_toggle_actions (actions,
1151 layerview_toggle_entries,
1152 N_LAYER_BUTTONS, port);
1154 gtk_action_group_add_toggle_actions (actions,
1155 routestyle_toggle_entries,
1156 N_ROUTE_STYLES, port);
1162 * Make a frame for the top menubar, load in actions for the menus and
1163 * load the ui_manager string.
1165 static void
1166 make_top_menubar (GtkWidget * hbox, GHidPort * port)
1168 GtkUIManager *ui;
1169 GtkWidget *frame;
1170 GtkActionGroup *actions;
1171 GError *error = NULL;
1173 frame = gtk_frame_new (NULL);
1174 gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
1175 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
1177 ui = gtk_ui_manager_new ();
1178 ghidgui->ui_manager = ui;
1180 actions = gtk_action_group_new ("Actions");
1181 gtk_action_group_set_translation_domain (actions, NULL);
1182 ghidgui->main_actions = actions;
1184 make_menu_actions (actions, port);
1186 gtk_ui_manager_insert_action_group (ui, actions, 0);
1188 gtk_window_add_accel_group (GTK_WINDOW (gport->top_window),
1189 gtk_ui_manager_get_accel_group (ui));
1191 if (!gtk_ui_manager_add_ui_from_string (ui, new_ui_info, -1, &error))
1193 g_message ("building menus failed: %s", error->message);
1194 g_error_free (error);
1197 gtk_ui_manager_set_add_tearoffs (ui, TRUE);
1199 gtk_container_add (GTK_CONTAINER (frame),
1200 gtk_ui_manager_get_widget (ui, "/MenuBar"));
1205 /* Set the PCB name on a label or on the window title bar.
1207 void
1208 ghid_window_set_name_label (gchar * name)
1210 gchar *str;
1212 /* FIXME -- should this happen? It does... */
1213 /* This happens if we're calling an exporter from the command line */
1214 if (ghidgui == NULL)
1215 return;
1217 dup_string (&(ghidgui->name_label_string), name);
1218 if (!ghidgui->name_label_string || !*ghidgui->name_label_string)
1219 ghidgui->name_label_string = g_strdup (_("Unnamed"));
1221 if (!ghidgui->name_label)
1222 return;
1224 if (ghidgui->ghid_title_window)
1226 gtk_widget_hide (ghidgui->label_hbox);
1227 str = g_strdup_printf ("PCB: %s", ghidgui->name_label_string);
1228 gtk_window_set_title (GTK_WINDOW (gport->top_window), str);
1230 else
1232 gtk_widget_show (ghidgui->label_hbox);
1233 str = g_strdup_printf (" <b><big>%s</big></b> ",
1234 ghidgui->name_label_string);
1235 gtk_label_set_markup (GTK_LABEL (ghidgui->name_label), str);
1236 gtk_window_set_title (GTK_WINDOW (gport->top_window), "PCB");
1238 g_free (str);
1241 static void
1242 grid_units_button_cb (GtkWidget * widget, gpointer data)
1245 /* Do handling common to when units are changed from the menu.
1247 handle_grid_units_change (!Settings.grid_units_mm);
1252 * The two following callbacks are used to keep the absolute
1253 * and relative cursor labels from growing and shrinking as you
1254 * move the cursor around.
1256 static void
1257 absolute_label_size_req_cb (GtkWidget * widget,
1258 GtkRequisition *req, gpointer data)
1261 static gint w = 0;
1262 if (req->width > w)
1263 w = req->width;
1264 else
1265 req->width = w;
1268 static void
1269 relative_label_size_req_cb (GtkWidget * widget,
1270 GtkRequisition *req, gpointer data)
1273 static gint w = 0;
1274 if (req->width > w)
1275 w = req->width;
1276 else
1277 req->width = w;
1280 static void
1281 make_cursor_position_labels (GtkWidget * hbox, GHidPort * port)
1283 GtkWidget *frame, *label, *button;
1285 /* The grid units button next to the cursor position labels.
1287 button = gtk_button_new ();
1288 label = gtk_label_new ("");
1289 gtk_label_set_markup (GTK_LABEL (label),
1290 Settings.grid_units_mm ?
1291 "<b>mm</b> " : "<b>mil</b> ");
1292 ghidgui->grid_units_label = label;
1293 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
1294 gtk_container_add (GTK_CONTAINER (button), label);
1295 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, TRUE, 0);
1296 g_signal_connect (G_OBJECT (button), "clicked",
1297 G_CALLBACK (grid_units_button_cb), NULL);
1299 /* The absolute cursor position label
1301 frame = gtk_frame_new (NULL);
1302 gtk_box_pack_end (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
1303 gtk_container_border_width (GTK_CONTAINER (frame), 2);
1304 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
1306 label = gtk_label_new ("");
1307 gtk_container_add (GTK_CONTAINER (frame), label);
1308 ghidgui->cursor_position_absolute_label = label;
1309 g_signal_connect (G_OBJECT (label), "size-request",
1310 G_CALLBACK (absolute_label_size_req_cb), NULL);
1313 /* The relative cursor position label
1315 frame = gtk_frame_new (NULL);
1316 gtk_box_pack_end (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
1317 gtk_container_border_width (GTK_CONTAINER (frame), 2);
1318 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
1319 label = gtk_label_new (" __.__ __.__ ");
1320 gtk_container_add (GTK_CONTAINER (frame), label);
1321 ghidgui->cursor_position_relative_label = label;
1322 g_signal_connect (G_OBJECT (label), "size-request",
1323 G_CALLBACK (relative_label_size_req_cb), NULL);
1328 /* ------------------------------------------------------------------
1329 | Handle the layer buttons.
1331 static LayerButtonSet layer_buttons[N_LAYER_BUTTONS];
1333 static gint layer_select_button_index;
1335 static gboolean layer_enable_button_cb_hold_off,
1336 layer_select_button_cb_hold_off;
1338 static void
1339 layer_select_button_cb (GtkWidget * widget, LayerButtonSet * lb)
1341 gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
1342 static gboolean in_cb = FALSE;
1344 if (!active || layer_select_button_cb_hold_off || in_cb)
1345 return;
1347 in_cb = TRUE;
1349 PCB->SilkActive = (lb->index == LAYER_BUTTON_SILK);
1350 PCB->RatDraw = (lb->index == LAYER_BUTTON_RATS);
1352 if (lb->index < max_layer)
1353 ChangeGroupVisibility (lb->index, true, true);
1355 layer_select_button_index = lb->index;
1357 layer_select_button_cb_hold_off = TRUE;
1358 layer_enable_button_cb_hold_off = TRUE;
1359 ghid_layer_buttons_update ();
1360 layer_select_button_cb_hold_off = FALSE;
1361 layer_enable_button_cb_hold_off = FALSE;
1363 ghid_invalidate_all ();
1364 in_cb = FALSE;
1367 static void
1368 layer_enable_button_cb (GtkWidget * widget, gpointer data)
1370 LayerButtonSet *lb;
1371 gint i, group, layer = GPOINTER_TO_INT (data);
1372 gboolean active, redraw = FALSE;
1374 active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
1376 if (layer_enable_button_cb_hold_off)
1377 return;
1379 lb = &layer_buttons[layer];
1380 switch (layer)
1382 case LAYER_BUTTON_SILK:
1383 PCB->ElementOn = active;
1384 PCB->Data->SILKLAYER.On = PCB->ElementOn;
1385 PCB->Data->BACKSILKLAYER.On = PCB->ElementOn;
1386 redraw = 1;
1387 break;
1389 case LAYER_BUTTON_RATS:
1390 PCB->RatOn = active;
1391 redraw = 1;
1392 break;
1394 case LAYER_BUTTON_PINS:
1395 PCB->PinOn = active;
1396 redraw |= (PCB->Data->ElementN != 0);
1397 break;
1399 case LAYER_BUTTON_VIAS:
1400 PCB->ViaOn = active;
1401 redraw |= (PCB->Data->ViaN != 0);
1402 break;
1404 case LAYER_BUTTON_FARSIDE:
1405 PCB->InvisibleObjectsOn = active;
1406 PCB->Data->BACKSILKLAYER.On = (active && PCB->ElementOn);
1407 redraw = TRUE;
1408 break;
1410 case LAYER_BUTTON_MASK:
1411 if (active)
1412 SET_FLAG (SHOWMASKFLAG, PCB);
1413 else
1414 CLEAR_FLAG (SHOWMASKFLAG, PCB);
1415 redraw = TRUE;
1416 break;
1418 default:
1419 /* check if active layer is in the group;
1420 | if YES, make a different one active if possible. Logic from
1421 | Xt PCB code.
1423 if ((group = GetGroupOfLayer (layer)) ==
1424 GetGroupOfLayer (MIN (max_layer, INDEXOFCURRENT)))
1426 for (i = (layer + 1) % (max_layer + 1); i != layer;
1427 i = (i + 1) % (max_layer + 1))
1428 if (PCB->Data->Layer[i].On == true &&
1429 GetGroupOfLayer (i) != group)
1430 break;
1431 if (i != layer)
1433 ChangeGroupVisibility ((int) i, true, true);
1435 else
1437 /* everything else off, we can't turn this off too */
1438 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
1439 return;
1442 /* switch layer group on/off */
1443 ChangeGroupVisibility (layer, active, false);
1444 redraw = TRUE;
1445 break;
1448 layer_select_button_cb_hold_off = TRUE;
1449 layer_enable_button_cb_hold_off = TRUE;
1450 ghid_layer_buttons_update ();
1451 layer_select_button_cb_hold_off = FALSE;
1452 layer_enable_button_cb_hold_off = FALSE;
1454 if (redraw)
1455 ghid_invalidate_all();
1458 static void
1459 layer_button_set_color (LayerButtonSet * lb, gchar * color_string)
1461 GdkColor color;
1463 if (!lb->layer_enable_ebox)
1464 return;
1466 color.red = color.green = color.blue = 0;
1467 ghid_map_color_string (color_string, &color);
1468 gtk_widget_modify_bg (lb->layer_enable_ebox, GTK_STATE_ACTIVE, &color);
1469 gtk_widget_modify_bg (lb->layer_enable_ebox, GTK_STATE_PRELIGHT, &color);
1471 gtk_widget_modify_fg (lb->label, GTK_STATE_ACTIVE, &WhitePixel);
1474 void
1475 layer_enable_button_set_label (GtkWidget * label, gchar * text)
1477 gchar *s;
1479 if (ghidgui->small_label_markup)
1480 s = g_strdup_printf ("<small>%s</small>", text);
1481 else
1482 s = g_strdup (text);
1483 gtk_label_set_markup (GTK_LABEL (label), s);
1484 g_free (s);
1487 static void
1488 ghid_show_layer_buttons(void)
1490 LayerButtonSet *lb;
1491 gint i;
1493 for (i = 0; i < MAX_LAYER; ++i)
1495 lb = &layer_buttons[i];
1496 if (i < max_layer)
1498 gtk_widget_show(lb->layer_enable_button);
1499 gtk_widget_show(lb->radio_select_button);
1501 else
1503 gtk_widget_hide(lb->layer_enable_button);
1504 gtk_widget_hide(lb->radio_select_button);
1509 /* After layers comes some special cases. Since silk and netlist (rats)
1510 | are selectable as separate drawing areas, they are more consistently
1511 | placed after the layers in the gui so the select radio buttons will
1512 | be grouped. This is different from Xt PCB which had a different looking
1513 | select interface.
1515 static void
1516 make_layer_buttons (GtkWidget * vbox, GHidPort * port)
1518 LayerButtonSet *lb;
1519 GtkWidget *table, *ebox, *label, *button, *hbox;
1520 GSList *group = NULL;
1521 gchar *text;
1522 gint i;
1523 gchar *color_string;
1524 gboolean active = TRUE;
1526 hbox = gtk_hbox_new (FALSE, 0);
1527 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 4);
1528 table = gtk_table_new (N_LAYER_BUTTONS, 2, FALSE);
1529 gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, 3);
1531 for (i = 0; i < N_LAYER_BUTTONS; ++i)
1533 lb = &layer_buttons[i];
1534 lb->index = i;
1536 if (i < N_SELECTABLE_LAYER_BUTTONS)
1538 button = gtk_radio_button_new (group);
1539 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
1540 gtk_table_attach_defaults (GTK_TABLE (table), button,
1541 0, 1, i, i + 1);
1543 lb->radio_select_button = button;
1544 g_signal_connect (G_OBJECT (button), "toggled",
1545 G_CALLBACK (layer_select_button_cb), lb);
1548 layer_process (&color_string, &text, &active, i);
1550 button = gtk_check_button_new ();
1551 label = gtk_label_new ("");
1552 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
1553 layer_enable_button_set_label (label, text);
1555 ebox = gtk_event_box_new ();
1556 gtk_container_add (GTK_CONTAINER (ebox), label);
1557 gtk_container_add (GTK_CONTAINER (button), ebox);
1558 gtk_table_attach_defaults (GTK_TABLE (table), button, 1, 2, i, i + 1);
1559 /* gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); */
1560 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE);
1562 lb->layer_enable_button = button;
1563 lb->layer_enable_ebox = ebox;
1564 lb->text = g_strdup (text);
1565 lb->label = label;
1567 layer_button_set_color (lb, color_string);
1568 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), active);
1570 g_signal_connect (G_OBJECT (button), "toggled",
1571 G_CALLBACK (layer_enable_button_cb),
1572 GINT_TO_POINTER (i));
1579 /* If new color scheme is loaded from the config or user changes a color
1580 | in the preferences, make sure our layer button colors get updated.
1582 void
1583 ghid_layer_buttons_color_update (void)
1585 gchar *color_string;
1586 LayerButtonSet *lb;
1587 gint i;
1589 if (!gport->drawing_area)
1590 return;
1592 /* Fixme: should the color set be maintained in both the PCB and the
1593 | Settings struct?
1595 pcb_colors_from_settings (PCB);
1597 for (i = 0; i < N_LAYER_BUTTONS; ++i)
1599 lb = &layer_buttons[i];
1601 layer_process (&color_string, NULL, NULL, i);
1603 layer_button_set_color (lb, color_string);
1608 /* Update layer button labels and enabled state to match current PCB.
1610 void
1611 ghid_layer_enable_buttons_update (void)
1613 LayerButtonSet *lb;
1614 gchar *s;
1615 gint i;
1617 #ifdef DEBUG_MENUS
1618 printf ("ghid_layer_enable_buttons_update()\n");
1619 #endif
1621 /* Update layer button labels and active state to state inside of PCB
1623 layer_enable_button_cb_hold_off = TRUE;
1624 for (i = 0; i < max_layer; ++i)
1626 lb = &layer_buttons[i];
1627 s = UNKNOWN (PCB->Data->Layer[i].Name);
1628 if (dup_string (&lb->text, s))
1630 layer_enable_button_set_label (lb->label, _(s));
1631 ghid_config_layer_name_update (_(s), i);
1633 if (Settings.verbose)
1635 gboolean active, new;
1637 active =
1638 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
1639 (lb->layer_enable_button));
1640 new = PCB->Data->Layer[i].On;
1641 if (active != new)
1642 printf ("ghid_layer_enable_buttons_update: active=%d new=%d\n",
1643 active, new);
1645 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
1646 (lb->layer_enable_button),
1647 PCB->Data->Layer[i].On);
1649 /* Buttons for elements (silk), rats, pins, vias, and far side don't
1650 | change labels.
1652 lb = &layer_buttons[LAYER_BUTTON_SILK];
1653 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lb->layer_enable_button),
1654 PCB->ElementOn);
1656 lb = &layer_buttons[LAYER_BUTTON_RATS];
1657 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lb->layer_enable_button),
1658 PCB->RatOn);
1660 lb = &layer_buttons[LAYER_BUTTON_PINS];
1661 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lb->layer_enable_button),
1662 PCB->PinOn);
1664 lb = &layer_buttons[LAYER_BUTTON_VIAS];
1665 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lb->layer_enable_button),
1666 PCB->ViaOn);
1668 lb = &layer_buttons[LAYER_BUTTON_FARSIDE];
1669 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lb->layer_enable_button),
1670 PCB->InvisibleObjectsOn);
1671 layer_enable_button_cb_hold_off = FALSE;
1674 void
1675 ghid_layer_button_select (gint layer)
1677 if (layer != layer_select_button_index)
1679 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
1680 (layer_buttons[layer].
1681 radio_select_button), TRUE);
1682 layer_select_button_index = layer;
1686 /* Main layer button synchronization with current PCB state. Called when
1687 | user toggles layer visibility or changes drawing layer or when internal
1688 | PCB code changes layer visibility.
1691 void
1692 ghid_layer_buttons_update (void)
1694 gint layer;
1695 gboolean active = FALSE;
1696 gboolean old_holdoff;
1697 char tmpnm[40];
1698 int i;
1699 int set;
1700 gchar *text;
1701 GtkAction *a;
1702 GValue setfalse = { 0 };
1703 GValue settrue = { 0 };
1704 GValue setlabel = { 0 };
1706 g_value_init (&setfalse, G_TYPE_BOOLEAN);
1707 g_value_init (&settrue, G_TYPE_BOOLEAN);
1708 g_value_set_boolean (&setfalse, FALSE);
1709 g_value_set_boolean (&settrue, TRUE);
1710 g_value_init (&setlabel, G_TYPE_STRING);
1712 #ifdef DEBUG_MENUS
1713 printf ("ghid_layer_buttons_update()\n");
1714 #endif
1716 if (!ghidgui || ghidgui->creating)
1717 return;
1719 ghid_layer_enable_buttons_update ();
1721 /* Turning off a layer that was selected will cause PCB to switch to
1722 | another layer.
1724 if (PCB->RatDraw)
1725 layer = LAYER_BUTTON_RATS;
1726 else
1727 layer = PCB->SilkActive ? LAYER_BUTTON_SILK : LayerStack[0];
1729 if (layer < max_layer)
1730 active = PCB->Data->Layer[layer].On;
1731 else if (layer == LAYER_BUTTON_SILK)
1732 active = PCB->ElementOn;
1733 else if (layer == LAYER_BUTTON_RATS)
1734 active = PCB->RatOn;
1736 if (Settings.verbose)
1738 printf ("ghid_layer_buttons_update cur_index=%d update_index=%d\n",
1739 layer_select_button_index, layer);
1740 if (active && layer != layer_select_button_index)
1741 printf ("\tActivating button %d\n", layer);
1744 /* mask the callbacks */
1745 old_holdoff = ghidgui->toggle_holdoff;
1746 ghidgui->toggle_holdoff = TRUE;
1748 /* update the check marks in the layer pick menu */
1749 for (i = 0; i < N_LAYER_BUTTONS ; i++)
1751 sprintf (tmpnm, "%s%d", LAYERPICK, i);
1752 a = gtk_action_group_get_action (ghidgui->main_actions, tmpnm);
1754 layer_process (NULL, &text, &set, i);
1755 g_value_set_string (&setlabel, text);
1757 if (a != NULL)
1759 g_object_set_property (G_OBJECT (a), "visible", (i >= max_layer && i < MAX_LAYER) ? &setfalse : &settrue);
1760 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (a), (set && (i == layer) ) ? TRUE : FALSE);
1761 g_object_set_property (G_OBJECT (a), "label", &setlabel);
1764 sprintf (tmpnm, "%s%d", LAYERVIEW, i);
1765 a = gtk_action_group_get_action (ghidgui->main_actions, tmpnm);
1766 if (a != NULL)
1768 g_object_set_property (G_OBJECT (a), "visible", (i >= max_layer && i < MAX_LAYER) ? &setfalse : &settrue);
1769 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (a), set ? TRUE : FALSE);
1770 g_value_set_string (&setlabel, text);
1771 g_object_set_property (G_OBJECT (a), "label", &setlabel);
1776 g_value_unset (&setfalse);
1777 g_value_unset (&settrue);
1778 g_value_unset (&setlabel);
1779 ghidgui->toggle_holdoff = old_holdoff;
1781 if (active && layer != layer_select_button_index)
1783 layer_select_button_cb_hold_off = TRUE;
1784 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
1785 (layer_buttons[layer].
1786 radio_select_button), TRUE);
1787 layer_select_button_index = layer;
1788 layer_select_button_cb_hold_off = FALSE;
1793 static void
1794 route_style_edit_cb (GtkWidget * widget, GHidPort * port)
1796 hid_action("AdjustStyle");
1799 static void
1800 route_style_select_button_cb (GtkToggleButton * button, gpointer data)
1802 RouteStyleType *rst;
1803 gchar buf[16];
1804 gint index = GPOINTER_TO_INT (data);
1806 if (ghidgui->toggle_holdoff || index == NUM_STYLES + 2)
1807 return;
1809 if (route_style_index == index)
1810 return;
1811 route_style_index = index;
1813 if (index < NUM_STYLES)
1815 snprintf (buf, sizeof (buf), "%d", index + 1);
1816 if (gtk_toggle_button_get_active (button))
1817 hid_actionl ("RouteStyle", buf, NULL);
1819 else if (index < NUM_STYLES + 2)
1821 rst = &route_style_button[index].route_style;
1822 SetLineSize (rst->Thick);
1823 SetViaSize (rst->Diameter, TRUE);
1824 SetViaDrillingHole (rst->Hole, TRUE);
1825 SetKeepawayWidth (rst->Keepaway);
1827 gtk_widget_set_sensitive (route_style_edit_button, TRUE);
1828 ghid_set_status_line_label();
1831 static void
1832 ghid_route_style_temp_buttons_hide (void)
1834 gtk_widget_hide (route_style_button[NUM_STYLES].button);
1835 gtk_widget_hide (route_style_button[NUM_STYLES + 1].button);
1837 /* This one never becomes visibile.
1839 gtk_widget_hide (route_style_button[NUM_STYLES + 2].button);
1843 static void
1844 make_route_style_buttons (GtkWidget * vbox, GHidPort * port)
1846 GtkWidget *button;
1847 GSList *group = NULL;
1848 RouteStyleButton *rbut;
1849 gint i;
1851 button = gtk_button_new_with_label (_("Route Style"));
1852 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 2);
1853 g_signal_connect (button, "clicked",
1854 G_CALLBACK (route_style_edit_cb), port);
1855 route_style_edit_button = button;
1857 for (i = 0; i < N_ROUTE_STYLES; ++i)
1859 RouteStyleType *rst;
1860 gchar buf[32];
1862 rbut = &route_style_button[i];
1863 if (i < NUM_STYLES)
1865 rst = &PCB->RouteStyle[i];
1866 button = gtk_radio_button_new_with_label (group, _(rst->Name));
1868 else
1870 snprintf (buf, sizeof (buf), _("Temp%d"), i - NUM_STYLES + 1);
1871 button = gtk_radio_button_new_with_label (group, buf);
1872 if (!route_style_button[i].route_style.Name)
1873 route_style_button[i].route_style.Name = g_strdup (buf);
1875 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
1876 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
1877 rbut->button = button;
1878 if (i < NUM_STYLES + 2)
1879 g_signal_connect (G_OBJECT (button), "toggled",
1880 G_CALLBACK (route_style_select_button_cb),
1881 GINT_TO_POINTER (i));
1885 void
1886 ghid_route_style_button_set_active (gint n)
1888 if (n < 0 || n >= N_ROUTE_STYLES)
1889 return;
1891 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
1892 (route_style_button[n].button), TRUE);
1895 /* Upate the route style button selected to match current route settings.
1896 | If user has changed an in use route setting so they don't match any
1897 | defined route style, select the invisible dummy route style button.
1899 void
1900 ghid_route_style_buttons_update (void)
1902 RouteStyleType *rst;
1903 gint i;
1905 for (i = 0; i < NUM_STYLES + 2; ++i)
1907 if (i < NUM_STYLES)
1908 rst = &PCB->RouteStyle[i];
1909 else
1911 if (!route_style_button[i].shown) /* Temp button shown? */
1912 continue;
1913 rst = &route_style_button[i].route_style;
1915 if (Settings.LineThickness == rst->Thick
1916 && Settings.ViaThickness == rst->Diameter
1917 && Settings.ViaDrillingHole == rst->Hole
1918 && Settings.Keepaway == rst->Keepaway)
1919 break;
1921 /* If i == NUM_STYLES + 2 at this point, we activate the invisible button.
1923 ghidgui->toggle_holdoff = TRUE;
1924 ghid_route_style_button_set_active (i);
1925 route_style_index = i;
1926 ghidgui->toggle_holdoff = FALSE;
1928 gtk_widget_set_sensitive (route_style_edit_button,
1929 (i == NUM_STYLES + 2) ? FALSE : TRUE);
1932 void
1933 ghid_route_style_set_button_label (gchar * name, gint index)
1935 if (index < 0 || index >= NUM_STYLES || !route_style_button[index].button)
1936 return;
1937 gtk_button_set_label (GTK_BUTTON (route_style_button[index].button),
1938 _(name));
1941 void
1942 ghid_route_style_set_temp_style (RouteStyleType * rst, gint which)
1944 RouteStyleButton *rsb;
1945 gchar *tmp;
1946 gint index = which + NUM_STYLES;
1948 if (which < 0 || which > 1)
1949 return;
1950 rsb = &route_style_button[index];
1951 gtk_widget_show (rsb->button);
1952 rsb->shown = TRUE;
1953 tmp = rsb->route_style.Name;
1954 rsb->route_style = *rst;
1955 rsb->route_style.Name = tmp;
1956 if (route_style_index != index)
1958 route_style_index = index; /* Sets already done */
1959 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (rsb->button), TRUE);
1966 * ---------------------------------------------------------------
1967 * Mode buttons
1969 typedef struct
1971 GtkWidget *button, *box0, *box1;
1972 gchar *name;
1973 gint mode;
1974 gchar **xpm;
1976 ModeButton;
1979 static ModeButton mode_buttons[] = {
1980 {NULL, NULL, NULL, "via", VIA_MODE, via},
1981 {NULL, NULL, NULL, "line", LINE_MODE, line},
1982 {NULL, NULL, NULL, "arc", ARC_MODE, arc},
1983 {NULL, NULL, NULL, "text", TEXT_MODE, text},
1984 {NULL, NULL, NULL, "rectangle", RECTANGLE_MODE, rect},
1985 {NULL, NULL, NULL, "polygon", POLYGON_MODE, poly},
1986 {NULL, NULL, NULL, "polygonhole", POLYGONHOLE_MODE, polyhole},
1987 {NULL, NULL, NULL, "buffer", PASTEBUFFER_MODE, buf},
1988 {NULL, NULL, NULL, "remove", REMOVE_MODE, del},
1989 {NULL, NULL, NULL, "rotate", ROTATE_MODE, rot},
1990 {NULL, NULL, NULL, "insertPoint", INSERTPOINT_MODE, ins},
1991 {NULL, NULL, NULL, "thermal", THERMAL_MODE, thrm},
1992 {NULL, NULL, NULL, "select", ARROW_MODE, sel},
1993 {NULL, NULL, NULL, "lock", LOCK_MODE, lock}
1996 static gint n_mode_buttons = G_N_ELEMENTS (mode_buttons);
1999 static void
2000 mode_button_toggled_cb (GtkWidget * widget, ModeButton * mb)
2002 gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
2004 if (active)
2006 SetMode (mb->mode);
2007 ghid_mode_cursor (mb->mode);
2008 ghidgui->settings_mode = mb->mode;
2012 void
2013 ghid_mode_buttons_update (void)
2015 ModeButton *mb;
2016 gint i;
2018 for (i = 0; i < n_mode_buttons; ++i)
2020 mb = &mode_buttons[i];
2021 if (Settings.Mode == mb->mode)
2023 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->button), TRUE);
2024 break;
2029 void
2030 ghid_pack_mode_buttons(void)
2032 ModeButton *mb;
2033 gint i;
2034 static gint last_pack_compact = -1;
2036 if (last_pack_compact >= 0)
2038 if (last_pack_compact)
2039 gtk_container_remove(GTK_CONTAINER(ghidgui->mode_buttons1_vbox),
2040 ghidgui->mode_buttons1_frame);
2041 else
2042 gtk_container_remove(GTK_CONTAINER(ghidgui->mode_buttons0_frame_vbox),
2043 ghidgui->mode_buttons0_frame);
2045 for (i = 0; i < n_mode_buttons; ++i)
2047 mb = &mode_buttons[i];
2048 if (last_pack_compact)
2049 gtk_container_remove (GTK_CONTAINER (mb->box1), mb->button);
2050 else
2051 gtk_container_remove (GTK_CONTAINER (mb->box0), mb->button);
2054 for (i = 0; i < n_mode_buttons; ++i)
2056 mb = &mode_buttons[i];
2057 if (ghidgui->compact_vertical)
2058 gtk_box_pack_start (GTK_BOX (mb->box1), mb->button, FALSE, FALSE, 0);
2059 else
2060 gtk_box_pack_start (GTK_BOX (mb->box0), mb->button, FALSE, FALSE, 0);
2062 if (ghidgui->compact_vertical)
2064 gtk_box_pack_start(GTK_BOX(ghidgui->mode_buttons1_vbox),
2065 ghidgui->mode_buttons1_frame, FALSE, FALSE, 0);
2066 gtk_widget_show_all(ghidgui->mode_buttons1_frame);
2068 else
2070 gtk_box_pack_start(GTK_BOX(ghidgui->mode_buttons0_frame_vbox),
2071 ghidgui->mode_buttons0_frame, FALSE, FALSE, 0);
2072 gtk_widget_show_all(ghidgui->mode_buttons0_frame);
2074 last_pack_compact = ghidgui->compact_vertical;
2077 static void
2078 make_mode_buttons (GHidPort * port)
2080 ModeButton *mb;
2081 GtkWidget *hbox0 = NULL, *button;
2082 GtkWidget *image;
2083 GdkPixbuf *pixbuf;
2084 GSList *group = NULL;
2085 gint i;
2087 for (i = 0; i < n_mode_buttons; ++i)
2089 mb = &mode_buttons[i];
2090 button = gtk_radio_button_new (group);
2091 mb->button = button;
2092 g_object_ref(G_OBJECT(mb->button));
2093 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
2094 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE);
2096 if ((i % ghidgui->n_mode_button_columns) == 0)
2098 hbox0 = gtk_hbox_new (FALSE, 0);
2099 gtk_box_pack_start (GTK_BOX (ghidgui->mode_buttons0_vbox),
2100 hbox0, FALSE, FALSE, 0);
2102 mb->box0 = hbox0;
2104 mb->box1 = ghidgui->mode_buttons1_hbox;
2106 pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **) mb->xpm);
2107 image = gtk_image_new_from_pixbuf (pixbuf);
2108 g_object_unref (G_OBJECT (pixbuf));
2110 gtk_container_add (GTK_CONTAINER (button), image);
2111 if (!strcmp (mb->name, "select"))
2112 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2113 g_signal_connect (button, "toggled",
2114 G_CALLBACK (mode_button_toggled_cb), mb);
2116 ghid_pack_mode_buttons();
2120 * ---------------------------------------------------------------
2121 * Top window
2122 * ---------------------------------------------------------------
2125 static GtkWidget *ghid_left_sensitive_box;
2127 static gint
2128 delete_chart_cb (GtkWidget * widget, GdkEvent * event, GHidPort * port)
2130 ghid_config_files_write ();
2131 hid_action ("Quit");
2134 * Return TRUE to keep our app running. A FALSE here would let the
2135 * delete signal continue on and kill our program.
2137 return TRUE;
2140 static void
2141 destroy_chart_cb (GtkWidget * widget, GHidPort * port)
2143 gtk_main_quit ();
2149 * Create the top_window contents. The config settings should be loaded
2150 * before this is called.
2152 static void
2153 ghid_build_pcb_top_window (void)
2155 GtkWidget *window;
2156 GtkWidget *vbox_main, *vbox_left, *hbox_middle, *hbox = NULL;
2157 GtkWidget *viewport, *ebox, *vbox, *frame;
2158 GtkWidget *label;
2159 GHidPort *port = &ghid_port;
2160 gchar *s;
2161 GtkWidget *scrolled;
2163 window = gport->top_window;
2165 vbox_main = gtk_vbox_new (FALSE, 0);
2166 gtk_container_add (GTK_CONTAINER (window), vbox_main);
2168 /* -- Top control bar */
2169 hbox = gtk_hbox_new (FALSE, 4);
2170 gtk_box_pack_start (GTK_BOX (vbox_main), hbox, FALSE, FALSE, 0);
2171 ghidgui->top_hbox = hbox;
2174 * menu_hbox will be made insensitive when the gui needs
2175 * a modal button GetLocation button press.
2177 ghidgui->menu_hbox = gtk_hbox_new (FALSE, 0);
2178 gtk_box_pack_start (GTK_BOX (ghidgui->top_hbox), ghidgui->menu_hbox,
2179 FALSE, FALSE, 0);
2180 vbox = gtk_vbox_new(FALSE, 0);
2181 gtk_box_pack_start(GTK_BOX(ghidgui->menu_hbox), vbox, FALSE, FALSE, 0);
2182 hbox = gtk_hbox_new(FALSE, 0);
2183 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
2185 ghid_load_menus ();
2186 make_top_menubar(hbox, port);
2188 frame = gtk_frame_new(NULL);
2189 gtk_widget_show(frame);
2190 g_object_ref(G_OBJECT(frame));
2191 ghidgui->mode_buttons1_vbox = vbox;
2192 ghidgui->mode_buttons1_frame = frame;
2193 ghidgui->mode_buttons1_hbox = gtk_hbox_new (FALSE, 0);
2194 gtk_container_add(GTK_CONTAINER(frame), ghidgui->mode_buttons1_hbox);
2196 vbox = gtk_vbox_new(FALSE, 0);
2197 gtk_box_pack_end(GTK_BOX(ghidgui->top_hbox), vbox,
2198 FALSE, FALSE, 0);
2199 ghidgui->compact_vbox = gtk_vbox_new (FALSE, 0);
2200 gtk_box_pack_end (GTK_BOX (ghidgui->top_hbox), ghidgui->compact_vbox,
2201 FALSE, FALSE, 0);
2203 ghidgui->compact_hbox = gtk_hbox_new (FALSE, 0);
2204 gtk_box_pack_start(GTK_BOX(vbox), ghidgui->compact_hbox, TRUE, FALSE, 0);
2207 * The board name is optionally in compact_vbox and the position
2208 * labels will be packed below or to the side.
2210 hbox = gtk_hbox_new (FALSE, 0);
2211 gtk_box_pack_start (GTK_BOX (ghidgui->compact_vbox), hbox, TRUE, FALSE, 2);
2212 ghidgui->label_hbox = hbox;
2214 label = gtk_label_new ("");
2215 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
2216 if (ghidgui->name_label_string)
2218 g_strdup_printf (" <b><big>%s</big></b> ", ghidgui->name_label_string);
2219 else
2220 s = g_strdup ("<b><big>%s</big></b>");
2221 gtk_label_set_markup (GTK_LABEL (label), s);
2222 g_free (s);
2223 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 4);
2224 ghidgui->name_label = label;
2227 * The position_box pack location depends on user setting of
2228 * compact horizontal mode.
2230 ghidgui->position_hbox = gtk_hbox_new (FALSE, 0);
2231 g_object_ref(G_OBJECT(ghidgui->position_hbox)); /* so can remove it */
2232 if (ghidgui->compact_horizontal)
2234 gtk_box_pack_end (GTK_BOX (ghidgui->compact_vbox),
2235 ghidgui->position_hbox, TRUE, FALSE, 0);
2237 else
2239 gtk_box_pack_end(GTK_BOX(ghidgui->compact_hbox), ghidgui->position_hbox,
2240 FALSE, FALSE, 4);
2243 make_cursor_position_labels (ghidgui->position_hbox, port);
2245 hbox_middle = gtk_hbox_new (FALSE, 0);
2246 gtk_box_pack_start (GTK_BOX (vbox_main), hbox_middle, TRUE, TRUE, 3);
2249 /* -- Left control bar */
2250 ebox = gtk_event_box_new ();
2251 gtk_widget_set_events (ebox, GDK_EXPOSURE_MASK);
2252 gtk_box_pack_start (GTK_BOX (hbox_middle), ebox, FALSE, FALSE, 3);
2255 * This box will also be made insensitive when the gui needs
2256 * a modal button GetLocation button press.
2258 ghid_left_sensitive_box = ebox;
2260 vbox_left = gtk_vbox_new (FALSE, 0);
2261 gtk_container_add (GTK_CONTAINER (ebox), vbox_left);
2263 vbox = ghid_scrolled_vbox(vbox_left, &scrolled,
2264 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
2265 make_layer_buttons(vbox, port);
2267 vbox = gtk_vbox_new(FALSE, 0);
2268 gtk_box_pack_start(GTK_BOX(vbox_left), vbox, FALSE, FALSE, 0);
2269 ghidgui->mode_buttons0_frame_vbox = vbox;
2270 frame = gtk_frame_new(NULL);
2271 ghidgui->mode_buttons0_frame = frame;
2272 gtk_widget_show(frame);
2273 g_object_ref(G_OBJECT(frame));
2274 ghidgui->mode_buttons0_vbox = gtk_vbox_new(FALSE, 0);
2275 gtk_container_add(GTK_CONTAINER(frame), ghidgui->mode_buttons0_vbox);
2276 make_mode_buttons (port);
2278 frame = gtk_frame_new(NULL);
2279 gtk_box_pack_end(GTK_BOX(vbox_left), frame, FALSE, FALSE, 0);
2280 vbox = gtk_vbox_new(FALSE, 0);
2281 gtk_container_add(GTK_CONTAINER(frame), vbox);
2282 hbox = gtk_hbox_new(FALSE, 0);
2283 gtk_box_pack_start(GTK_BOX (vbox), hbox, FALSE, FALSE, 1);
2284 vbox = gtk_vbox_new(FALSE, 0);
2285 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 4);
2286 make_route_style_buttons(vbox, port);
2288 vbox = gtk_vbox_new (FALSE, 0);
2289 gtk_box_pack_start (GTK_BOX (hbox_middle), vbox, TRUE, TRUE, 0);
2291 hbox = gtk_hbox_new (FALSE, 0);
2292 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
2294 /* -- The PCB layout output drawing area */
2295 viewport = gtk_viewport_new (NULL, NULL);
2296 gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_IN);
2297 gtk_box_pack_start (GTK_BOX (hbox), viewport, TRUE, TRUE, 0);
2299 gport->drawing_area = gtk_drawing_area_new ();
2301 gtk_widget_add_events (gport->drawing_area, GDK_EXPOSURE_MASK
2302 | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
2303 | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK
2304 | GDK_KEY_RELEASE_MASK | GDK_KEY_PRESS_MASK
2305 | GDK_FOCUS_CHANGE_MASK | GDK_POINTER_MOTION_MASK);
2308 * This is required to get the drawing_area key-press-event. Also the
2309 * enter and button press callbacks grab focus to be sure we have it
2310 * when in the drawing_area.
2312 GTK_WIDGET_SET_FLAGS (gport->drawing_area, GTK_CAN_FOCUS);
2314 gtk_container_add (GTK_CONTAINER (viewport), gport->drawing_area);
2316 ghidgui->v_adjustment = gtk_adjustment_new (0.0, 0.0, 100.0,
2317 10.0, 10.0, 10.0);
2318 ghidgui->v_range =
2319 gtk_vscrollbar_new (GTK_ADJUSTMENT (ghidgui->v_adjustment));
2321 gtk_range_set_update_policy (GTK_RANGE (ghidgui->v_range),
2322 GTK_UPDATE_CONTINUOUS);
2323 gtk_box_pack_start (GTK_BOX (hbox), ghidgui->v_range, FALSE, FALSE, 0);
2325 g_signal_connect (G_OBJECT (ghidgui->v_adjustment), "value_changed",
2326 G_CALLBACK (v_adjustment_changed_cb), ghidgui);
2328 ghidgui->h_adjustment = gtk_adjustment_new (0.0, 0.0, 100.0,
2329 10.0, 10.0, 10.0);
2330 ghidgui->h_range =
2331 gtk_hscrollbar_new (GTK_ADJUSTMENT (ghidgui->h_adjustment));
2332 gtk_range_set_update_policy (GTK_RANGE (ghidgui->h_range),
2333 GTK_UPDATE_CONTINUOUS);
2334 gtk_box_pack_start (GTK_BOX (vbox), ghidgui->h_range, FALSE, FALSE, 0);
2336 g_signal_connect (G_OBJECT (ghidgui->h_adjustment), "value_changed",
2337 G_CALLBACK (h_adjustment_changed_cb), ghidgui);
2339 /* -- The bottom status line label */
2340 ghidgui->status_line_hbox = gtk_hbox_new (FALSE, 0);
2341 gtk_box_pack_start (GTK_BOX (vbox), ghidgui->status_line_hbox,
2342 FALSE, FALSE, 2);
2344 label = gtk_label_new ("");
2345 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
2346 gtk_box_pack_start (GTK_BOX (ghidgui->status_line_hbox), label, FALSE,
2347 FALSE, 0);
2348 ghidgui->status_line_label = label;
2350 /* Depending on user setting, the command_combo_box may get packed into
2351 | the status_line_hbox, but it will happen on demand the first time
2352 | the user does a command entry.
2355 g_signal_connect (G_OBJECT (gport->drawing_area), "expose_event",
2356 G_CALLBACK (ghid_port_drawing_area_expose_event_cb),
2357 port);
2358 g_signal_connect (G_OBJECT (gport->top_window), "configure_event",
2359 G_CALLBACK (top_window_configure_event_cb), port);
2360 g_signal_connect (G_OBJECT (gport->drawing_area), "configure_event",
2361 G_CALLBACK (ghid_port_drawing_area_configure_event_cb),
2362 port);
2365 /* Mouse and key events will need to be intercepted when PCB needs a
2366 | location from the user.
2369 ghid_interface_input_signals_connect ();
2371 g_signal_connect (G_OBJECT (gport->drawing_area), "scroll_event",
2372 G_CALLBACK (ghid_port_window_mouse_scroll_cb), port);
2373 g_signal_connect (G_OBJECT (gport->drawing_area), "enter_notify_event",
2374 G_CALLBACK (ghid_port_window_enter_cb), port);
2375 g_signal_connect (G_OBJECT (gport->drawing_area), "leave_notify_event",
2376 G_CALLBACK (ghid_port_window_leave_cb), port);
2377 g_signal_connect (G_OBJECT (gport->drawing_area), "motion_notify_event",
2378 G_CALLBACK (ghid_port_window_motion_cb), port);
2382 g_signal_connect (G_OBJECT (window), "delete_event",
2383 G_CALLBACK (delete_chart_cb), port);
2384 g_signal_connect (G_OBJECT (window), "destroy",
2385 G_CALLBACK (destroy_chart_cb), port);
2387 ghidgui->creating = FALSE;
2389 gtk_widget_show_all (gport->top_window);
2390 gtk_widget_realize (vbox_main);
2391 gtk_widget_realize (hbox_middle);
2392 gtk_widget_realize (viewport);
2393 gtk_widget_realize (gport->drawing_area);
2394 gdk_window_set_back_pixmap (gport->drawing_area->window, NULL, FALSE);
2396 ghid_route_style_temp_buttons_hide ();
2397 ghid_show_layer_buttons();
2401 /* Connect and disconnect just the signals a g_main_loop() will need.
2402 | Cursor and motion events still need to be handled by the top level
2403 | loop, so don't connect/reconnect these.
2404 | A g_main_loop will be running when PCB wants the user to select a
2405 | location or if command entry is needed in the status line hbox.
2406 | During these times normal button/key presses are intercepted, either
2407 | by new signal handlers or the command_combo_box entry.
2409 static gulong button_press_handler, button_release_handler,
2410 key_press_handler, key_release_handler;
2412 void
2413 ghid_interface_input_signals_connect (void)
2415 button_press_handler =
2416 g_signal_connect (G_OBJECT (gport->drawing_area), "button_press_event",
2417 G_CALLBACK (ghid_port_button_press_cb),
2418 ghidgui->ui_manager);
2420 button_release_handler =
2421 g_signal_connect (G_OBJECT (gport->drawing_area), "button_release_event",
2422 G_CALLBACK (ghid_port_button_release_cb),
2423 ghidgui->ui_manager);
2425 key_press_handler =
2426 g_signal_connect (G_OBJECT (gport->drawing_area), "key_press_event",
2427 G_CALLBACK (ghid_port_key_press_cb),
2428 ghidgui->ui_manager);
2430 key_release_handler =
2431 g_signal_connect (G_OBJECT (gport->drawing_area), "key_release_event",
2432 G_CALLBACK (ghid_port_key_release_cb),
2433 ghidgui->ui_manager);
2436 void
2437 ghid_interface_input_signals_disconnect (void)
2439 if (button_press_handler)
2440 g_signal_handler_disconnect (gport->drawing_area, button_press_handler);
2442 if (button_release_handler)
2443 g_signal_handler_disconnect (gport->drawing_area, button_release_handler);
2445 if (key_press_handler)
2446 g_signal_handler_disconnect (gport->drawing_area, key_press_handler);
2448 if (key_release_handler)
2449 g_signal_handler_disconnect (gport->drawing_area, key_release_handler);
2451 button_press_handler = button_release_handler = 0;
2452 key_press_handler = key_release_handler = 0;
2457 /* We'll set the interface insensitive when a g_main_loop is running so the
2458 | Gtk menus and buttons don't respond and interfere with the special entry
2459 | the user needs to be doing.
2461 void
2462 ghid_interface_set_sensitive (gboolean sensitive)
2464 gtk_widget_set_sensitive (ghid_left_sensitive_box, sensitive);
2465 gtk_widget_set_sensitive (ghidgui->menu_hbox, sensitive);
2469 /* ----------------------------------------------------------------------
2470 * initializes icon pixmap and also cursor bit maps
2472 static void
2473 ghid_init_icons (GHidPort * port)
2475 XC_clock_source = gdk_bitmap_create_from_data (gport->top_window->window,
2476 (char *) rotateIcon_bits,
2477 rotateIcon_width,
2478 rotateIcon_height);
2479 XC_clock_mask =
2480 gdk_bitmap_create_from_data (gport->top_window->window, (char *) rotateMask_bits,
2481 rotateMask_width, rotateMask_height);
2483 XC_hand_source = gdk_bitmap_create_from_data (gport->top_window->window,
2484 (char *) handIcon_bits,
2485 handIcon_width,
2486 handIcon_height);
2487 XC_hand_mask =
2488 gdk_bitmap_create_from_data (gport->top_window->window, (char *) handMask_bits,
2489 handMask_width, handMask_height);
2491 XC_lock_source = gdk_bitmap_create_from_data (gport->top_window->window,
2492 (char *) lockIcon_bits,
2493 lockIcon_width,
2494 lockIcon_height);
2495 XC_lock_mask =
2496 gdk_bitmap_create_from_data (gport->top_window->window, (char *) lockMask_bits,
2497 lockMask_width, lockMask_height);
2500 void
2501 ghid_create_pcb_widgets (void)
2503 GHidPort *port = &ghid_port;
2504 GError *err = NULL;
2506 gdk_color_parse ("white", &WhitePixel);
2507 gdk_color_parse ("black", &BlackPixel);
2509 if (bg_image_file)
2510 ghidgui->bg_pixbuf = gdk_pixbuf_new_from_file(bg_image_file, &err);
2511 if (err)
2513 g_error("%s", err->message);
2514 g_error_free(err);
2516 ghid_build_pcb_top_window ();
2517 ghid_update_toggle_flags ();
2519 ghid_init_icons (port);
2520 SetMode (ARROW_MODE);
2521 ghid_mode_buttons_update ();
2524 static gboolean
2525 ghid_listener_cb (GIOChannel *source,
2526 GIOCondition condition,
2527 gpointer data)
2529 GIOStatus status;
2530 gchar *str;
2531 gsize len;
2532 gsize term;
2533 GError *err = NULL;
2536 if (condition & G_IO_HUP)
2538 gui->log ("Read end of pipe died!\n");
2539 return FALSE;
2542 if (condition == G_IO_IN)
2544 status = g_io_channel_read_line (source, &str, &len, &term, &err);
2545 switch (status)
2547 case G_IO_STATUS_NORMAL:
2548 hid_parse_actions (str);
2549 g_free (str);
2550 break;
2552 case G_IO_STATUS_ERROR:
2553 gui->log ("ERROR status from g_io_channel_read_line\n");
2554 return FALSE;
2555 break;
2557 case G_IO_STATUS_EOF:
2558 gui->log ("Input pipe returned EOF. The --listen option is \n"
2559 "probably not running anymore in this session.\n");
2560 return FALSE;
2561 break;
2563 case G_IO_STATUS_AGAIN:
2564 gui->log ("AGAIN status from g_io_channel_read_line\n");
2565 return FALSE;
2566 break;
2568 default:
2569 fprintf (stderr, "ERROR: unhandled case in ghid_listener_cb\n");
2570 return FALSE;
2571 break;
2575 else
2576 fprintf (stderr, "Unknown condition in ghid_listener_cb\n");
2578 return TRUE;
2581 static void
2582 ghid_create_listener (void)
2584 guint tag;
2585 GIOChannel *channel;
2586 int fd = fileno (stdin);
2588 channel = g_io_channel_unix_new (fd);
2589 tag = g_io_add_watch (channel, G_IO_IN, ghid_listener_cb, NULL);
2593 /* ------------------------------------------------------------ */
2594 static int stdin_listen = 0;
2595 HID_Attribute ghid_attribute_list[] = {
2596 {"listen", "Listen for actions on stdin",
2597 HID_Boolean, 0, 0, {0, 0, 0}, 0, &stdin_listen},
2598 #define HA_listen 0
2600 {"bg-image", "Background Image",
2601 HID_String, 0, 0, {0, 0, 0}, 0, &bg_image_file},
2602 #define HA_bg_image 1
2606 REGISTER_ATTRIBUTES (ghid_attribute_list)
2608 /* Create top level window for routines that will need top_window
2609 | before ghid_create_pcb_widgets() is called.
2611 void
2612 ghid_parse_arguments (int *argc, char ***argv)
2614 GtkWidget *window;
2615 gint i;
2616 GdkPixbuf *icon;
2618 /* on windows we need to figure out the installation directory */
2619 #ifdef WIN32
2620 char * tmps;
2621 char * libdir;
2622 tmps = g_win32_get_package_installation_directory(PACKAGE "-" VERSION, NULL);
2623 #define REST_OF_PATH G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S PACKAGE G_DIR_SEPARATOR_S "newlib"
2624 libdir = (char *) malloc(strlen(tmps) +
2625 strlen(REST_OF_PATH) +
2627 sprintf(libdir, "%s%s", tmps, REST_OF_PATH);
2628 free(tmps);
2630 Settings.LibraryTree = libdir;
2632 #undef REST_OF_PATH
2634 #endif
2636 #if defined (DEBUG)
2637 for (i = 0; i < *argc; i++)
2639 printf ("ghid_parse_arguments(): *argv[%d] = \"%s\"\n", i, (*argv)[i]);
2641 #endif
2643 /* Threads aren't used in PCB, but this call would go here.
2645 /* g_thread_init (NULL); */
2647 #if defined (ENABLE_NLS)
2648 /* Do our own setlocale() stufff since we want to override LC_NUMERIC
2650 gtk_set_locale ();
2651 setlocale (LC_NUMERIC, "POSIX"); /* use decimal point instead of comma */
2652 #endif
2655 * Prevent gtk_init() and gtk_init_check() from automatically
2656 * calling setlocale (LC_ALL, "") which would undo LC_NUMERIC if ENABLE_NLS
2657 * We also don't want locale set if no ENABLE_NLS to keep POSIX LC_NUMERIC.
2659 gtk_disable_setlocale ();
2661 gtk_init (argc, argv);
2663 gport = &ghid_port;
2664 gport->zoom = 300.0;
2665 pixel_slop = 300;
2667 ghid_config_files_read (argc, argv);
2669 Settings.AutoPlace = 0;
2670 for (i = 0; i < *argc; i++)
2672 if (strcmp ((*argv)[i], "-auto-place") == 0)
2673 Settings.AutoPlace = 1;
2676 #ifdef ENABLE_NLS
2677 #ifdef LOCALEDIR
2678 bindtextdomain (PACKAGE, LOCALEDIR);
2679 #endif
2680 textdomain (PACKAGE);
2681 bind_textdomain_codeset (PACKAGE, "UTF-8");
2682 #endif /* ENABLE_NLS */
2684 icon = gdk_pixbuf_new_from_xpm_data ((const gchar **) icon_bits);
2685 gtk_window_set_default_icon (icon);
2687 window = gport->top_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2688 gtk_window_set_title (GTK_WINDOW (window), "PCB");
2689 gtk_window_set_default_size(GTK_WINDOW(window),
2690 ghidgui->top_window_width, ghidgui->top_window_height);
2692 if (Settings.AutoPlace)
2693 gtk_widget_set_uposition (GTK_WIDGET (window), 10, 10);
2695 gtk_widget_realize (gport->top_window);
2696 gtk_widget_show_all (gport->top_window);
2697 ghidgui->creating = TRUE;
2700 void
2701 ghid_do_export (HID_Attr_Val * options)
2703 ghid_create_pcb_widgets ();
2705 /* These are needed to make sure the @layerpick and @layerview menus
2706 * are properly initialized and synchronized with the current PCB.
2708 ghid_layer_buttons_update ();
2709 ghid_show_layer_buttons();
2711 if (stdin_listen)
2712 ghid_create_listener ();
2714 ghid_notify_gui_is_up ();
2716 gtk_main ();
2717 ghid_config_files_write ();
2721 gint
2722 LayersChanged (int argc, char **argv, int px, int py)
2724 if (!ghidgui || !ghidgui->ui_manager)
2725 return 0;
2727 ghid_config_groups_changed();
2728 ghid_layer_buttons_update ();
2729 ghid_show_layer_buttons();
2731 /* FIXME - if a layer is moved it should retain its color. But layers
2732 | currently can't do that because color info is not saved in the
2733 | pcb file. So this makes a moved layer change its color to reflect
2734 | the way it will be when the pcb is reloaded.
2736 pcb_colors_from_settings (PCB);
2737 return 0;
2740 static const char toggleview_syntax[] =
2741 "ToggleView(1..MAXLAYER)\n"
2742 "ToggleView(layername)\n"
2743 "ToggleView(Silk|Rats|Pins|Vias|Mask|BackSide)";
2745 static const char toggleview_help[] =
2746 "Toggle the visibility of the specified layer or layer group.";
2748 /* %start-doc actions ToggleView
2750 If you pass an integer, that layer is specified by index (the first
2751 layer is @code{1}, etc). If you pass a layer name, that layer is
2752 specified by name. When a layer is specified, the visibility of the
2753 layer group containing that layer is toggled.
2755 If you pass a special layer name, the visibility of those components
2756 (silk, rats, etc) is toggled. Note that if you have a layer named
2757 the same as a special layer, the layer is chosen over the special layer.
2759 %end-doc */
2761 static int
2762 ToggleView (int argc, char **argv, int x, int y)
2764 int i, l;
2765 static gboolean in_toggle_view = 0;
2766 gboolean active;
2768 #ifdef DEBUG_MENUS
2769 printf ("Starting ToggleView(). in_toggle_view = %d\n", in_toggle_view);
2770 #endif
2771 if (in_toggle_view)
2773 fprintf (stderr, "ToggleView() called on top of another ToggleView()\n"
2774 "Please report this and how it happened\n");
2775 return 0;
2778 in_toggle_view = 1;
2780 if (argc == 0)
2782 in_toggle_view = 0;
2783 AFAIL (toggleview);
2785 if (isdigit ((int) argv[0][0]))
2787 l = atoi (argv[0]) - 1;
2789 else if (strcmp (argv[0], "Silk") == 0)
2790 l = LAYER_BUTTON_SILK;
2791 else if (strcmp (argv[0], "Rats") == 0)
2792 l = LAYER_BUTTON_RATS;
2793 else if (strcmp (argv[0], "Pins") == 0)
2794 l = LAYER_BUTTON_PINS;
2795 else if (strcmp (argv[0], "Vias") == 0)
2796 l = LAYER_BUTTON_VIAS;
2797 else if (strcmp (argv[0], "Mask") == 0)
2798 l = LAYER_BUTTON_MASK;
2799 else if (strcmp (argv[0], "BackSide") == 0)
2800 l = LAYER_BUTTON_FARSIDE;
2801 else
2803 l = -1;
2804 for (i = 0; i < max_layer + 2; i++)
2805 if (strcmp (argv[0], PCB->Data->Layer[i].Name) == 0)
2807 l = i;
2808 break;
2810 if (l == -1)
2812 in_toggle_view = 0;
2813 AFAIL (toggleview);
2818 printf ("ToggleView(): l = %d\n", l);
2820 /* Now that we've figured out which toggle button ought to control
2821 * this layer, simply hit the button and let the pre-existing code deal
2823 active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (layer_buttons[l].layer_enable_button));
2825 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (layer_buttons[l].layer_enable_button),
2826 active == TRUE ? FALSE : TRUE);
2827 in_toggle_view = 0;
2828 return 0;
2831 static const char selectlayer_syntax[] =
2832 "SelectLayer(1..MAXLAYER|Silk|Rats)";
2834 static const char selectlayer_help[] =
2835 "Select which layer is the current layer.";
2837 /* %start-doc actions SelectLayer
2839 The specified layer becomes the currently active layer. It is made
2840 visible if it is not already visible
2842 %end-doc */
2844 static int
2845 SelectLayer (int argc, char **argv, int x, int y)
2847 int newl;
2848 if (argc == 0)
2849 AFAIL (selectlayer);
2851 if (strcasecmp (argv[0], "silk") == 0)
2852 newl = LAYER_BUTTON_SILK;
2853 else if (strcasecmp (argv[0], "rats") == 0)
2854 newl = LAYER_BUTTON_RATS;
2855 else
2856 newl = atoi (argv[0]) - 1;
2858 #ifdef DEBUG_MENUS
2859 printf ("SelectLayer(): newl = %d\n", newl);
2860 #endif
2862 /* Now that we've figured out which radio button ought to select
2863 * this layer, simply hit the button and let the pre-existing code deal
2865 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (layer_buttons[newl].radio_select_button),
2866 TRUE);
2868 return 0;
2872 HID_Action gtk_topwindow_action_list[] = {
2873 {"LayersChanged", 0, LayersChanged,
2874 layerschanged_help, layerschanged_syntax},
2875 {"SelectLayer", 0, SelectLayer,
2876 selectlayer_help, selectlayer_syntax},
2877 {"ToggleView", 0, ToggleView,
2878 toggleview_help, toggleview_syntax}
2881 REGISTER_ACTIONS (gtk_topwindow_action_list)
2883 static char *pcbmenu_path = "gpcb-menu.res";
2885 static HID_Attribute pcbmenu_attr[] = {
2886 {"pcb-menu", "Location of gpcb-menu.res file",
2887 HID_String, 0, 0, {0, PCBLIBDIR "/gpcb-menu.res", 0}, 0, &pcbmenu_path}
2890 REGISTER_ATTRIBUTES (pcbmenu_attr)
2893 * This function is used to check if a specified hotkey in the menu
2894 * resource file is "special". In this case "special" means that gtk
2895 * assigns a particular meaning to it and the normal menu setup will
2896 * never see these key presses. We capture those and feed them back
2897 * into the menu callbacks. This function is called as new
2898 * accelerators are added when the menus are being built
2900 static void ghid_check_special_key (const char *accel, const char *name)
2902 size_t len;
2903 unsigned int mods;
2904 unsigned int ind;
2906 if ( accel == NULL || *accel == '\0' )
2908 return ;
2911 #ifdef DEBUG_MENUS
2912 printf ("%s(\"%s\", \"%s\")\n", __FUNCTION__, accel, name);
2913 #endif
2915 mods = 0;
2916 if (strstr (accel, "<alt>") )
2918 mods |= GHID_KEY_ALT;
2920 if (strstr (accel, "<control>") )
2922 mods |= GHID_KEY_CONTROL;
2924 if (strstr (accel, "<shift>") )
2926 mods |= GHID_KEY_SHIFT;
2930 len = strlen (accel);
2932 #define CHECK_KEY(a) ((len >= strlen (a)) && (strcmp (accel + len - strlen (a), (a)) == 0))
2934 ind = 0;
2935 if ( CHECK_KEY ("Tab") )
2937 ind = mods | GHID_KEY_TAB;
2939 else if ( CHECK_KEY ("Up") )
2941 ind = mods | GHID_KEY_UP;
2943 else if ( CHECK_KEY ("Down") )
2945 ind = mods | GHID_KEY_DOWN;
2947 else if ( CHECK_KEY ("Left") )
2949 ind = mods | GHID_KEY_LEFT;
2951 else if ( CHECK_KEY ("Right") )
2953 ind = mods | GHID_KEY_RIGHT;
2956 if (ind > 0)
2958 if (ind >= (sizeof (ghid_hotkey_actions) / sizeof (char *)) )
2960 fprintf (stderr, "ERROR: overflow of the ghid_hotkey_actions array. Index = %d\n"
2961 "Please report this.\n", ind);
2962 exit (1);
2965 ghid_hotkey_actions[ind] = g_strdup (name);
2966 #ifdef DEBUG_MENUS
2967 printf ("Adding \"special\" hotkey to ghid_hotkey_actions[%u] :"
2968 " %s (%s)\n", ind, accel, name);
2969 #endif
2974 #define INDENT_INC 5
2976 static void
2977 ghid_append_action (const char * name, const char *stock_id,
2978 const char *label, const char *accelerator,
2979 const char *tooltip)
2982 #ifdef DEBUG_MENUS
2983 printf ("ghid_append_action(\"%s\", \"%s\", \"%s\", \"%s\", \"%s\")\n",
2984 UNKNOWN (name),
2985 UNKNOWN (stock_id),
2986 UNKNOWN (label),
2987 UNKNOWN (accelerator),
2988 UNKNOWN (tooltip));
2989 #endif
2991 accelerator = ghid_check_unique_accel (accelerator);
2993 if ( (new_entries = realloc (new_entries,
2994 (menuitem_cnt + 1) * sizeof (GtkActionEntry))) == NULL)
2996 fprintf (stderr, "ghid_append_action(): realloc of new_entries failed\n");
2997 exit (1);
3001 if ( (action_resources = realloc (action_resources,
3002 (menuitem_cnt + 1) * sizeof (Resource *))) == NULL)
3004 fprintf (stderr, "ghid_append_action(): realloc of action_resources failed\n");
3005 exit (1);
3007 action_resources[menuitem_cnt] = NULL;
3009 /* name, stock_id, label, accelerator, tooltip, callback */
3010 new_entries[menuitem_cnt].name = strdup (name);
3011 new_entries[menuitem_cnt].stock_id = (stock_id == NULL ? NULL : strdup (stock_id));
3012 new_entries[menuitem_cnt].label = strdup (label);
3013 new_entries[menuitem_cnt].accelerator = ( (accelerator == NULL || *accelerator == '\0')
3014 ? NULL : strdup (accelerator));
3015 new_entries[menuitem_cnt].tooltip = (tooltip == NULL ? NULL : strdup (tooltip));
3016 new_entries[menuitem_cnt].callback = G_CALLBACK (ghid_menu_cb);
3018 ghid_check_special_key (accelerator, name);
3019 menuitem_cnt++;
3022 static void
3023 ghid_append_toggle_action (const char * name, const char *stock_id,
3024 const char *label, const char *accelerator,
3025 const char *tooltip, int active)
3028 accelerator = ghid_check_unique_accel (accelerator);
3030 if ( (new_toggle_entries = realloc (new_toggle_entries,
3031 (tmenuitem_cnt + 1) * sizeof (GtkToggleActionEntry))) == NULL)
3033 fprintf (stderr, "ghid_append_toggle_action(): realloc of new_toggle_entries failed\n");
3034 exit (1);
3038 if ( (toggle_action_resources = realloc (toggle_action_resources,
3039 (tmenuitem_cnt + 1) * sizeof (Resource *))) == NULL)
3041 fprintf (stderr, "ghid_append_toggle_action(): realloc of toggle_action_resources failed\n");
3042 exit (1);
3044 toggle_action_resources[tmenuitem_cnt] = NULL;
3046 /* name, stock_id, label, accelerator, tooltip, callback */
3047 new_toggle_entries[tmenuitem_cnt].name = strdup (name);
3048 new_toggle_entries[tmenuitem_cnt].stock_id = (stock_id == NULL ? NULL : strdup (stock_id));
3049 new_toggle_entries[tmenuitem_cnt].label = strdup (label);
3050 new_toggle_entries[tmenuitem_cnt].accelerator = (accelerator == NULL ? NULL : strdup (accelerator));
3051 new_toggle_entries[tmenuitem_cnt].tooltip = (tooltip == NULL ? NULL : strdup (tooltip));
3052 new_toggle_entries[tmenuitem_cnt].callback = G_CALLBACK (ghid_menu_cb);
3053 new_toggle_entries[tmenuitem_cnt].is_active = active ? TRUE : FALSE;
3055 ghid_check_special_key (accelerator, name);
3056 tmenuitem_cnt++;
3060 * Some keys need to be replaced by a name for the gtk accelerators to
3061 * work. This table contains the translations. The "in" character is
3062 * what would appear in gpcb-menu.res and the "out" string is what we
3063 * have to feed to gtk. I was able to find these by using xev to find
3064 * the keycode and then looked at gtk+-2.10.9/gdk/keynames.txt (from the
3065 * gtk source distribution) to figure out the names that go with the
3066 * codes.
3068 typedef struct
3070 const char in;
3071 const char *out;
3072 } KeyTable;
3073 static KeyTable key_table[] =
3075 {':', "colon"},
3076 {'=', "equal"},
3077 {'/', "slash"},
3078 {'[', "bracketleft"},
3079 {']', "bracketright"},
3080 {'.', "period"},
3081 {'|', "bar"}
3083 static int n_key_table = sizeof (key_table) / sizeof (key_table[0]);
3085 static void
3086 add_resource_to_menu (char * menu, Resource * node, void * callback, int indent)
3088 int i, j;
3089 char *v;
3090 Resource *r;
3091 char tmps[32];
3092 char accel[64];
3093 int accel_n;
3094 char *menulabel = NULL;
3095 char ch[2];
3096 char m = '\0';
3097 char *cname = NULL;
3099 ch[1] = '\0';
3101 for (i = 0; i < node->c; i++)
3102 switch (resource_type (node->v[i]))
3104 case 101: /* named subnode */
3105 add_resource_to_menu (node->v[i].name, node->v[i].subres,
3106 callback, indent + INDENT_INC);
3107 break;
3109 case 1: /* unnamed subres */
3110 accel[0] = '\0';
3111 /* remaining number of chars available in accel (- 1 for '\0')*/
3112 accel_n = sizeof (accel) - 1;
3113 /* This is a menu choice. The first value in the unnamed
3114 * subres is what the menu choice gets called.
3116 * This may be a top level menu on the menubar,
3117 * a menu choice under, say the File menu, or
3118 * a menu choice under a submenu of a menu choice.
3120 * We need to pick off an "m" named resource which is
3121 * the menu accelerator key and an "a" named subresource
3122 * which contains the information for the hotkey.
3124 if ((v = resource_value (node->v[i].subres, "m")))
3126 #ifdef DEBUG_MENUS
3127 printf (" found resource value m=\"%s\"\n", v);
3128 #endif
3129 m = *v;
3131 if ((r = resource_subres (node->v[i].subres, "a")))
3133 /* for the accelerator, it has 2 values like
3135 * a={"Ctrl-Q" "Ctrl<Key>q"}
3136 * The first one is what's displayed in the menu and the
3137 * second actually defines the hotkey. Actually, the
3138 * first value is only used by the lesstif HID and is
3139 * ignored by the gtk HID. The second value is used by both.
3141 * We have to translate some strings. See
3142 * gtk+-2.10.9/gdk/keynames.txt from the gtk distribution
3143 * as well as the output from xev(1).
3145 * Modifiers:
3147 * "Ctrl" -> "<control>"
3148 * "Shift" -> "<shift>"
3149 * "Alt" -> "<alt>"
3150 * "<Key>" -> ""
3152 * keys:
3154 * " " -> ""
3155 * "Enter" -> "Return"
3158 char *p;
3159 int j;
3160 enum {KEY, MOD} state;
3162 state = MOD;
3163 #ifdef DEBUG_MENUS
3164 printf (" accelerator a=%p. r->v[0].value = \"%s\", r->v[1].value = \"%s\" ",
3165 r, r->v[0].value, r->v[1].value);
3166 #endif
3167 p = r->v[1].value;
3168 while (*p != '\0')
3170 switch (state)
3172 case MOD:
3173 if (*p == ' ')
3175 p++;
3177 else if (strncmp (p, "<Key>", 5) == 0)
3179 state = KEY;
3180 p += 5;
3182 else if (strncmp (p, "Ctrl", 4) == 0)
3184 strncat (accel, "<control>", accel_n);
3185 accel_n -= strlen ("<control>");
3186 p += 4;
3188 else if (strncmp (p, "Shift", 5) == 0)
3190 strncat (accel, "<shift>", accel_n);
3191 accel_n -= strlen ("<shift>");
3192 p += 5;
3194 else if (strncmp (p, "Alt", 3) == 0)
3196 strncat (accel, "<alt>", accel_n);
3197 accel_n -= strlen ("<alt>");
3198 p += 3;
3200 else
3202 static int gave_msg = 0;
3203 Message (_("Don't know how to parse \"%s\" as an accelerator in the menu resource file.\n"),
3206 if (! gave_msg)
3208 gave_msg = 1;
3209 Message (_("Format is:\n"
3210 "modifiers<Key>k\n"
3211 "where \"modifiers\" is a space separated list of key modifiers\n"
3212 "and \"k\" is the name of the key.\n"
3213 "Allowed modifiers are:\n"
3214 " Ctrl\n"
3215 " Shift\n"
3216 " Alt\n"
3217 "Please note that case is important.\n"));
3219 /* skip processing the rest */
3220 accel[0] = '\0';
3221 accel_n = sizeof (accel) - 1;
3222 p += strlen (p);
3224 break;
3226 case KEY:
3227 if (strncmp (p, "Enter", 5) == 0)
3229 strncat (accel, "Return", accel_n);
3230 accel_n -= strlen ("Return");
3231 p += 5;
3233 else
3235 ch[0] = *p;
3236 for (j = 0; j < n_key_table; j++)
3238 if ( *p == key_table[j].in)
3240 strncat (accel, key_table[j].out, accel_n);
3241 accel_n -= strlen (key_table[j].out);
3242 j = n_key_table;
3246 if (j == n_key_table)
3248 strncat (accel, ch, accel_n);
3249 accel_n -= strlen (ch);
3252 p++;
3254 break;
3258 if (G_UNLIKELY (accel_n < 0))
3260 accel_n = 0;
3261 Message ("Accelerator \"%s\" is too long to be parsed.\n", r->v[1].value);
3262 accel[0] = '\0';
3263 accel_n = 0;
3264 /* skip processing the rest */
3265 p += strlen (p);
3268 #ifdef DEBUG_MENUS
3269 printf ("\n translated = \"%s\"\n", accel);
3270 #endif
3272 v = "button";
3274 /* Now look for the first unnamed value (not a subresource) to
3275 * figure out the name of the menu or the menuitem.
3277 * After this loop, v will be the name of the menu or menuitem.
3280 for (j = 0; j < node->v[i].subres->c; j++)
3281 if (resource_type (node->v[i].subres->v[j]) == 10)
3283 v = node->v[i].subres->v[j].value;
3284 break;
3287 if (m == '\0')
3288 menulabel = strdup (v);
3289 else
3291 /* we've been given a mneumonic so we need to insert an
3292 * "_" into the label. For example if the string is
3293 * "Quit Program" and we have m=Q, we'd need to produce
3294 * "_Quit Program".
3296 char *s1, *s2;
3297 size_t l;
3299 l = strlen (_(v)) + 2;
3300 #ifdef DEBUG_MENUS
3301 printf ("allocate %ld bytes\n", l);
3302 #endif
3303 if ( (menulabel = (char *) malloc ( l * sizeof (char)))
3304 == NULL)
3306 fprintf (stderr, "add_resource_to_menu(): malloc failed\n");
3307 exit (1);
3310 s1 = menulabel;
3311 s2 = _(v);
3312 while (*s2 != '\0')
3314 if (*s2 == m)
3316 /* add the underscore and quit looking for more
3317 * matches since we only want to add 1 underscore
3319 *s1 = '_';
3320 s1++;
3321 m = '\0';
3323 *s1 = *s2;
3324 s1++;
3325 s2++;
3327 *s1 = '\0';
3329 #ifdef DEBUG_MENUS
3330 printf ("v = \"%s\", label = \"%s\"\n", v, menulabel);
3331 #endif
3332 /* if the subresource we're processing also has unnamed
3333 * subresources then this is either a menu (that goes on the
3334 * menu bar) or it is a submenu. It isn't a menuitem.
3336 if (node->v[i].subres->flags & FLAG_S)
3338 /* This is a menu */
3340 /* add menus to the same entries list as the "normal"
3341 * menuitems. We'll just use NULL for what happens so the
3342 * callback doesn't have anything to do.
3345 sprintf (tmps, "%s%d", MENUITEM, menuitem_cnt);
3346 cname = strdup (tmps);
3348 /* add to the action entries */
3349 /* name, stock_id, label, accelerator, tooltip */
3350 ghid_append_action (tmps, NULL, menulabel, accel, NULL);
3352 /* and add to the user interfact XML description */
3353 ghid_ui_info_indent (indent);
3354 ghid_ui_info_append ("<menu action='");
3355 ghid_ui_info_append (tmps);
3356 ghid_ui_info_append ("'>\n");
3359 /* recursively add more submenus or menuitems to this
3360 * menu/submenu
3362 add_resource_to_menu ("sub menu", node->v[i].subres,
3363 callback, indent + INDENT_INC);
3364 ghid_ui_info_indent (indent);
3366 /* and close this menu */
3367 ghid_ui_info_append ("</menu>\n");
3369 else
3371 /* We are in a specific menu choice and need to figure out
3372 * if it is a "normal" one
3373 * or if there is some condtion under which it is checked
3374 * or if it has sensitive=false which is simply a label
3377 char *checked = resource_value (node->v[i].subres, "checked");
3378 char *label = resource_value (node->v[i].subres, "sensitive");
3379 char *tip = resource_value (node->v[i].subres, "tip");
3380 if (checked)
3382 /* We have the "checked=" named value for this
3383 * menuitem. Now see if it is
3384 * checked=foo
3385 * or
3386 * checked=foo,bar
3388 * where the former is just a binary flag and the
3389 * latter is checking a flag against a value
3391 #ifdef DEBUG_MENUS
3392 printf ("Found a \"checked\" menu choice \"%s\", \"%s\"\n", v, checked);
3393 #endif
3394 if (strchr (checked, ','))
3396 /* we're comparing a flag against a value */
3397 #ifdef DEBUG_MENUS
3398 printf ("Found checked comparing a flag to a value\n");
3399 #endif
3401 else
3403 /* we're looking at a binary flag */
3404 /* name, stock_id, label, accelerator, tooltip, callback, is_active
3405 printf ("Found checked using a flag as a binary\n");
3410 sprintf (tmps, "%s%d", TMENUITEM, tmenuitem_cnt);
3411 cname = strdup (tmps);
3413 /* add to the action entries */
3414 /* name, stock_id, label, accelerator, tooltip, is_active */
3415 ghid_append_toggle_action (tmps, NULL, menulabel, accel, tip, 1);
3417 ghid_ui_info_indent (indent);
3418 ghid_ui_info_append ("<menuitem action='");
3419 ghid_ui_info_append (tmps);
3420 ghid_ui_info_append ("'/>\n");
3422 toggle_action_resources[tmenuitem_cnt-1] = node->v[i].subres;
3425 else if (label && strcmp (label, "false") == 0)
3427 /* we have sensitive=false so just put a label in the
3428 * GUI -- FIXME -- actually do something here....
3431 else
3434 * Here we are finally at the rest of an actual
3435 * menuitem. So, we need to get the subresource
3436 * that has all the actions in it (actually, it will
3437 * be the entire subresource that defines the
3438 * menuitem, the callbacks later will pick out the
3439 * actions part.
3441 * We add this resource to an array of action
3442 * resources that is used by the main menu callback to
3443 * figure out what really needs to be done.
3446 sprintf (tmps, "%s%d", MENUITEM, menuitem_cnt);
3447 cname = strdup (tmps);
3449 /* add to the action entries */
3450 /* name, stock_id, label, accelerator, tooltip */
3451 ghid_append_action (tmps, NULL, menulabel, accel, tip);
3453 ghid_ui_info_indent (indent);
3454 ghid_ui_info_append ("<menuitem action='");
3455 ghid_ui_info_append (tmps);
3456 ghid_ui_info_append ("'/>\n");
3459 action_resources[menuitem_cnt-1] = node->v[i].subres;
3461 #ifdef DEBUG_MENUS
3462 /* Print out the actions to help with debugging */
3464 int vi;
3465 Resource *mynode = node->v[i].subres;
3467 /* Start at the 2nd sub resource because the first
3468 * is the text that shows up in the menu.
3470 * We're looking for the unnamed values since those
3471 * are the ones which are actions.
3473 for (vi = 1; vi < mynode->c; vi++)
3474 if (resource_type (mynode->v[vi]) == 10)
3475 printf(" action value=\"%s\"\n", mynode->v[vi].value);
3477 #endif
3483 /* now keep looking over our menuitem to see if there is
3484 * any more work.
3486 for (j = 0; j < node->v[i].subres->c; j++)
3487 switch (resource_type (node->v[i].subres->v[j]))
3489 case 110: /* named value = X resource */
3491 char *n = node->v[i].subres->v[j].name;
3492 /* allow fg and bg to be abbreviations for
3493 * foreground and background
3495 if (strcmp (n, "fg") == 0)
3496 n = "foreground";
3497 if (strcmp (n, "bg") == 0)
3498 n = "background";
3500 /* ignore special named values (m, a, sensitive) */
3501 if (strcmp (n, "m") == 0
3502 || strcmp (n, "a") == 0
3503 || strcmp (n, "sensitive") == 0
3504 || strcmp (n, "tip") == 0
3506 break;
3508 /* log checked and active special values */
3509 if (strcmp (n, "checked") == 0)
3511 #ifdef DEBUG_MENUS
3512 printf ("%s is checked\n", node->v[i].subres->v[j].value);
3513 #endif
3514 note_toggle_flag (new_toggle_entries[tmenuitem_cnt-1].name,
3515 GHID_FLAG_CHECKED,
3516 node->v[i].subres->v[j].value);
3517 break;
3519 if (strcmp (n, "active") == 0)
3521 if (cname != NULL)
3523 note_toggle_flag (cname,
3524 GHID_FLAG_ACTIVE,
3525 node->v[i].subres->v[j].value);
3527 else
3529 printf ("WARNING: %s cname == NULL\n", __FUNCTION__);
3531 break;
3534 /* if we got this far it is supposed to be an X
3535 * resource. For now ignore it and warn the user
3537 Message (_("The gtk gui currently ignores \"%s\""
3538 "as part of a menuitem resource.\n"
3539 "Feel free to provide patches\n"),
3540 node->v[i].subres->v[j].value);
3542 break;
3546 break;
3548 case 10: /* unnamed value */
3549 /* in the resource file we may have something like:
3551 * {File
3552 * {Open OpenAction()}
3553 * {Close CloseAction()}
3555 * {"Some Choice" MyAction()}
3556 * {"Some Other Choice" MyOtherAction()}
3557 * @foo
3558 * {Quit QuitAction()}
3561 * If we get here in the code it is becuase we found the "-"
3562 * or the "@foo".
3565 #ifdef DEBUG_MENUS
3566 printf ("resource_type for node #%d is 10 (unnamed value). value=\"%s\"\n",
3567 i, node->v[i].value);
3568 #endif
3570 if (node->v[i].value[0] == '@')
3572 if (strcmp (node->v[i].value, "@layerview") == 0)
3574 int i;
3575 char tmpid[40];
3576 for (i = 0 ; i < N_LAYER_BUTTONS; i++)
3578 sprintf (tmpid, "<menuitem action='%s%d' />\n",
3579 LAYERVIEW, i);
3580 ghid_ui_info_indent (indent);
3581 ghid_ui_info_append (tmpid);
3584 else if (strcmp (node->v[i].value, "@layerpick") == 0)
3586 int i;
3587 char tmpid[40];
3588 for (i = 0 ; i < N_SELECTABLE_LAYER_BUTTONS; i++)
3590 sprintf (tmpid, "<menuitem action='%s%d' />\n",
3591 LAYERPICK, i);
3592 ghid_ui_info_indent (indent);
3593 ghid_ui_info_append (tmpid);
3596 else if (strcmp (node->v[i].value, "@routestyles") == 0)
3598 int i;
3599 char tmpid[40];
3600 for (i = 0 ; i < N_ROUTE_STYLES; i++)
3602 sprintf (tmpid, "<menuitem action='%s%d' />\n",
3603 ROUTESTYLE, i);
3604 ghid_ui_info_indent (indent);
3605 ghid_ui_info_append (tmpid);
3608 else
3610 Message (_("GTK GUI currently ignores \"%s\" in the menu\n"
3611 "resource file.\n"), node->v[i].value);
3616 else if (strcmp (node->v[i].value, "-") == 0)
3618 ghid_ui_info_indent (indent);
3619 ghid_ui_info_append ("<separator/>\n");
3621 else if (i > 0)
3623 /* This is where you get with an action-less menuitem.
3624 * It is really just useful when you're starting to build
3625 * a new menu and you're looking to get the layout
3626 * right.
3628 sprintf (tmps, "%s%d", MENUITEM, menuitem_cnt);
3629 cname = strdup (tmps);
3631 /* add to the action entries
3632 * name, stock_id, label, accelerator, tooltip
3633 * Note that we didn't get the mneumonic added in here,
3634 * but since this is really for a dummy menu (no
3635 * associated actions), I'm not concerned.
3638 ghid_append_action (tmps, NULL, node->v[i].value, accel, NULL);
3640 ghid_ui_info_indent (indent);
3641 ghid_ui_info_append ("<menuitem action='");
3642 ghid_ui_info_append (tmps);
3643 ghid_ui_info_append ("'/>\n");
3645 action_resources[menuitem_cnt-1] = NULL;
3648 break;
3651 if (cname != NULL)
3652 free (cname);
3654 if (menulabel != NULL)
3655 free (menulabel);
3659 static void
3660 ghid_ui_info_indent (int indent)
3662 int i;
3664 for (i = 0; i < indent ; i++)
3666 ghid_ui_info_append (" ");
3671 *appends a string to the ui_info string
3672 * This function is used
3675 static void
3676 ghid_ui_info_append (const gchar * new)
3678 gchar *p;
3680 if (new_ui_info_sz == 0)
3682 new_ui_info_sz = 1024;
3683 new_ui_info = (gchar *) calloc ( new_ui_info_sz, sizeof (gchar));
3686 while (strlen (new_ui_info) + strlen (new) + 1 > new_ui_info_sz)
3688 size_t n;
3689 gchar * np;
3691 n = new_ui_info_sz + 1024;
3692 if ( (np = realloc (new_ui_info, n)) == NULL)
3694 fprintf (stderr, "ghid_ui_info_append(): realloc of size %ld failed\n",
3695 (long int) n);
3696 exit (1);
3698 new_ui_info = np;
3699 new_ui_info_sz = n;
3702 p = new_ui_info + strlen (new_ui_info) ;
3703 while (*new != '\0')
3705 *p = *new;
3706 p++;
3707 new++;
3710 *p = '\0';
3714 static void
3715 ghid_load_menus (void)
3717 char *filename;
3718 Resource *r = 0, *bir;
3719 char *home_pcbmenu;
3720 Resource *mr;
3721 int i;
3723 for (i = 0; i < sizeof (ghid_hotkey_actions) / sizeof (char *) ; i++)
3725 ghid_hotkey_actions[i] = NULL;
3728 /* homedir is set by the core */
3729 home_pcbmenu = NULL;
3730 if (homedir == NULL)
3732 Message (_("Warning: could not determine home directory\n"));
3734 else
3736 Message (_("Note: home directory is \"%s\"\n"), homedir);
3737 home_pcbmenu = Concat (homedir, PCB_DIR_SEPARATOR_S, ".pcb",
3738 PCB_DIR_SEPARATOR_S, "gpcb-menu.res", NULL);
3741 if (access ("gpcb-menu.res", R_OK) == 0)
3742 filename = "gpcb-menu.res";
3743 else if (home_pcbmenu != NULL && (access (home_pcbmenu, R_OK) == 0) )
3744 filename = home_pcbmenu;
3745 else if (access (pcbmenu_path, R_OK) == 0)
3746 filename = pcbmenu_path;
3747 else
3748 filename = 0;
3750 bir = resource_parse (0, gpcb_menu_default);
3751 if (!bir)
3753 fprintf (stderr, _("Error: internal menu resource didn't parse\n"));
3754 exit(1);
3757 if (filename)
3759 Message ("Loading menus from %s\n", filename);
3760 r = resource_parse (filename, 0);
3763 if (home_pcbmenu != NULL)
3765 free (home_pcbmenu);
3768 if (!r)
3770 Message ("Using default menus\n");
3771 r = bir;
3774 mr = resource_subres (r, "MainMenu");
3775 if (!mr)
3776 mr = resource_subres (bir, "MainMenu");
3778 if (mr)
3780 ghid_ui_info_append ("<ui>\n");
3781 ghid_ui_info_indent (INDENT_INC);
3782 ghid_ui_info_append ("<menubar name='MenuBar'>\n");
3783 add_resource_to_menu ("Initial Call", mr, 0, 2*INDENT_INC);
3784 ghid_ui_info_indent (INDENT_INC);
3785 ghid_ui_info_append ("</menubar>\n");
3788 mr = resource_subres (r, "PopupMenus");
3789 if (!mr)
3790 mr = resource_subres (bir, "PopupMenus");
3792 if (mr)
3794 int i;
3796 for (i = 0; i < mr->c; i++)
3798 if (resource_type (mr->v[i]) == 101)
3800 /* This is a named resource which defines a popup menu */
3801 ghid_ui_info_indent (INDENT_INC);
3802 ghid_ui_info_append ("<popup name='");
3803 ghid_ui_info_append (mr->v[i].name);
3804 ghid_ui_info_append ("'>\n");
3805 add_resource_to_menu ("Initial Call", mr->v[i].subres,
3806 0, 2*INDENT_INC);
3807 ghid_ui_info_indent (INDENT_INC);
3808 ghid_ui_info_append ("</popup>\n");
3810 else
3816 ghid_ui_info_append ("</ui>\n");
3818 #ifdef DEBUG_MENUS
3819 printf ("Finished loading menus. ui_info = \n");
3820 printf ("%s\n", new_ui_info);
3821 #endif
3823 mr = resource_subres (r, "Mouse");
3824 if (!mr)
3825 mr = resource_subres (bir, "Mouse");
3826 if (mr)
3827 load_mouse_resource (mr);
3831 /* ------------------------------------------------------------ */
3833 static const char adjuststyle_syntax[] =
3834 "AdjustStyle()\n";
3836 static const char adjuststyle_help[] =
3837 "Open the window which allows editing of the route styles";
3839 /* %start-doc actions AdjustStyle
3841 Opens the window which allows editing of the route styles.
3843 %end-doc */
3845 static int
3846 AdjustStyle(int argc, char **argv, int x, int y)
3848 RouteStyleType *rst = NULL;
3850 if (argc > 1)
3851 AFAIL (adjuststyle);
3853 if (route_style_index >= NUM_STYLES)
3854 rst = &route_style_button[route_style_index].route_style;
3855 ghid_route_style_dialog (route_style_index, rst);
3857 return 0;
3860 /* ------------------------------------------------------------ */
3862 static const char editlayergroups_syntax[] =
3863 "EditLayerGroups()\n";
3865 static const char editlayergroups_help[] =
3866 "Open the preferences window which allows editing of the layer groups";
3868 /* %start-doc actions EditLayerGroups
3870 Opens the preferences window which is where the layer groups
3871 are edited. This action is primarily provides to provide menu
3872 resource compatibility with the lesstif HID.
3874 %end-doc */
3876 static int
3877 EditLayerGroups(int argc, char **argv, int x, int y)
3880 if (argc != 0)
3881 AFAIL (editlayergroups);
3883 hid_actionl ("DoWindows", "Preferences", NULL);
3885 return 0;
3888 /* ------------------------------------------------------------ */
3890 HID_Action ghid_menu_action_list[] = {
3891 {"AdjustStyle", 0, AdjustStyle, adjuststyle_help, adjuststyle_syntax},
3892 {"EditLayerGroups", 0, EditLayerGroups, editlayergroups_help, editlayergroups_syntax}
3895 REGISTER_ACTIONS (ghid_menu_action_list)