Regenerate tests after "Make xy file output IPC 7531 compliant.".
[geda-pcb/kupson.git] / src / hid / gtk / gui-config.c
blob2f2e3fb02246f6df4ce363c2745deaaa9145880a
1 /*
2 * COPYRIGHT
4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 /* This file written by Bill Wilson for the PCB Gtk port.
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
31 #ifdef HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif
35 #include "gui.h"
36 #include "hid.h"
37 #include "../hidint.h"
38 #include "gtkhid.h"
40 #include "global.h"
41 #include "action.h"
42 #include "change.h"
43 #include "file.h"
44 #include "error.h"
45 #include "draw.h"
46 #include "misc.h" /* MKDIR() */
47 #include "pcb-printf.h"
48 #include "set.h"
50 #if 0
51 #include <locale.h>
52 #endif
53 #ifdef HAVE_LIBDMALLOC
54 #include <dmalloc.h>
55 #endif
57 extern int MoveLayerAction(int argc, char **argv, int x, int y);
58 /* This is defined in main.c */
59 void save_increments (const Increments *mm, const Increments *mil);
61 enum ConfigType
63 CONFIG_Boolean,
64 CONFIG_Integer,
65 CONFIG_Coord,
66 CONFIG_Real,
67 CONFIG_String,
68 CONFIG_Unused
71 typedef struct
73 gchar *name;
74 enum ConfigType type;
75 void *value;
77 ConfigAttribute;
80 enum ColorTypes
82 MISC_COLOR,
83 MISC_SELECTED_COLOR,
84 LAYER_COLOR,
85 LAYER_SELECTED_COLOR
88 typedef struct
90 HID_Attribute *attributes;
91 enum ColorTypes type;
92 GdkColor color;
93 gboolean color_is_mapped;
95 ConfigColor;
97 static GList *config_color_list, *lib_newlib_list;
99 static gchar *lib_newlib_config, *board_size_override;
102 static gchar *color_file;
104 extern void ghid_set_special_colors (HID_Attribute * ha);
107 #define PCB_CONFIG_DIR ".pcb"
108 #define PCB_CONFIG_FILE "preferences"
109 #define PCB_COLORS_DIR "colors"
111 static gchar *config_dir, *color_dir;
113 /* CONFIG_Unused types are expected to be found in main_attribute_list and
114 | will be assigned the type found there. NULL value pointers here are
115 | also expected to be assigned values from the main_attribute_list.
117 /* PinoutFont also not used anymore */
119 static ConfigAttribute config_attributes[] = {
120 {"gui-compact-horizontal", CONFIG_Boolean, &_ghidgui.compact_horizontal},
121 {"gui-compact-vertical", CONFIG_Boolean, &_ghidgui.compact_vertical},
122 {"use-command-window", CONFIG_Boolean, &_ghidgui.use_command_window},
123 {"save-in-tmp", CONFIG_Unused, NULL},
124 {"grid-units", CONFIG_Unused, NULL},
125 {"grid", CONFIG_Unused, NULL},
127 {"grid-increment-mm", CONFIG_Unused, NULL},
128 {"line-increment-mm", CONFIG_Unused, NULL},
129 {"size-increment-mm", CONFIG_Unused, NULL},
130 {"clear-increment-mm", CONFIG_Unused, NULL},
131 {"grid-increment-mil", CONFIG_Unused, NULL},
132 {"line-increment-mil", CONFIG_Unused, NULL},
133 {"size-increment-mil", CONFIG_Unused, NULL},
134 {"clear-increment-mil", CONFIG_Unused, NULL},
136 {"history-size", CONFIG_Integer, &_ghidgui.history_size},
137 {"top-window-width", CONFIG_Integer, &_ghidgui.top_window_width},
138 {"top-window-height", CONFIG_Integer, &_ghidgui.top_window_height},
139 {"log-window-width", CONFIG_Integer, &_ghidgui.log_window_width},
140 {"log-window-height", CONFIG_Integer, &_ghidgui.log_window_height},
141 {"drc-window-width", CONFIG_Integer, &_ghidgui.drc_window_width},
142 {"drc-window-height", CONFIG_Integer, &_ghidgui.drc_window_height},
143 {"library-window-width", CONFIG_Integer, &_ghidgui.library_window_width},
144 {"library-window-height", CONFIG_Integer, &_ghidgui.library_window_height},
145 {"netlist-window-height", CONFIG_Integer, &_ghidgui.netlist_window_height},
146 {"keyref-window-width", CONFIG_Integer, &_ghidgui.keyref_window_width},
147 {"keyref-window-height", CONFIG_Integer, &_ghidgui.keyref_window_height},
148 {"text-scale", CONFIG_Unused, NULL},
149 {"via-thickness", CONFIG_Unused, NULL},
150 {"via-drilling-hole", CONFIG_Unused, NULL},
151 {"backup-interval", CONFIG_Unused, NULL},
152 {"line-thickness", CONFIG_Unused, NULL},
153 {"rat-thickness", CONFIG_Unused, NULL},
154 {"bloat", CONFIG_Unused, NULL},
155 {"shrink", CONFIG_Unused, NULL},
156 {"min-width", CONFIG_Unused, NULL},
157 {"min-silk", CONFIG_Unused, NULL},
158 {"min-drill", CONFIG_Unused, NULL},
159 {"min-ring", CONFIG_Unused, NULL},
160 {"default-PCB-width", CONFIG_Unused, NULL},
161 {"default-PCB-height", CONFIG_Unused, NULL},
163 {"groups", CONFIG_Unused, NULL},
164 {"route-styles", CONFIG_Unused, NULL},
165 {"library-newlib", CONFIG_String, &lib_newlib_config},
166 {"color-file", CONFIG_String, &color_file},
167 /* FIXME: construct layer-names- in a list */
168 {"layer-name-1", CONFIG_Unused, NULL},
169 {"layer-name-2", CONFIG_Unused, NULL},
170 {"layer-name-3", CONFIG_Unused, NULL},
171 {"layer-name-4", CONFIG_Unused, NULL},
172 {"layer-name-5", CONFIG_Unused, NULL},
173 {"layer-name-6", CONFIG_Unused, NULL},
174 {"layer-name-7", CONFIG_Unused, NULL},
175 {"layer-name-8", CONFIG_Unused, NULL},
178 static gboolean
179 dup_core_string (gchar ** dst, const gchar * src)
181 if (dst == NULL || (*dst == NULL && src == NULL))
182 return FALSE;
184 if (*dst != NULL && src != NULL && strcmp (*dst, src) == 0)
185 return FALSE;
187 free (*dst);
188 *dst = (src == NULL) ? NULL : strdup (src);
190 return TRUE;
193 static FILE *
194 config_file_open (gchar * mode)
196 FILE *f;
197 gchar *homedir, *fname;
200 homedir = (gchar *) g_get_home_dir ();
201 if (!homedir)
203 g_message ("config_file_open: Can't get home directory!");
204 return NULL;
207 if (!config_dir)
209 config_dir =
210 g_build_path (G_DIR_SEPARATOR_S, homedir, PCB_CONFIG_DIR, NULL);
211 if (!g_file_test (config_dir, G_FILE_TEST_IS_DIR)
212 && MKDIR (config_dir, 0755) < 0)
214 g_message ("config_file_open: Can't make \"%s\" directory!",
215 config_dir);
216 g_free (config_dir);
217 config_dir = NULL;
218 return NULL;
222 if (!color_dir) /* Convenient to make the color dir here */
224 color_dir =
225 g_build_path (G_DIR_SEPARATOR_S, config_dir, PCB_COLORS_DIR, NULL);
226 if (!g_file_test (color_dir, G_FILE_TEST_IS_DIR))
228 if (MKDIR (color_dir, 0755) < 0)
230 g_message ("config_file_open: Can't make \"%s\" directory!",
231 color_dir);
232 g_free (color_dir);
233 color_dir = NULL;
235 fname = g_build_path (G_DIR_SEPARATOR_S,
236 color_dir, "Default", NULL);
237 dup_string (&color_file, fname);
238 g_free (fname);
242 fname = g_build_path (G_DIR_SEPARATOR_S, config_dir, PCB_CONFIG_FILE, NULL);
243 f = fopen (fname, mode);
245 g_free (fname);
246 return f;
249 static ConfigAttribute *
250 lookup_config_attribute (gchar * name, gboolean if_null_value)
252 ConfigAttribute *ca;
254 for (ca = &config_attributes[0];
255 ca < &config_attributes[0] + G_N_ELEMENTS (config_attributes); ++ca)
257 if (name && (!strcmp (name, ca->name)))
259 if (ca->value && if_null_value)
260 break;
261 return ca;
264 return NULL;
267 void
268 ghid_config_init (void)
270 HID_AttrNode *ha;
271 HID_Attribute *a;
272 ConfigAttribute *ca, dummy_attribute;
273 ConfigColor *cc;
274 gint len;
276 ghidgui->n_mode_button_columns = 3;
277 ghidgui->small_label_markup = TRUE;
278 ghidgui->history_size = 5;
279 dup_string (&color_file, "");
281 for (ha = hid_attr_nodes; ha; ha = ha->next)
283 for (a = ha->attributes; a < ha->attributes + ha->n; ++a)
285 if (!a->value)
286 continue;
287 if ((ca = lookup_config_attribute (a->name, TRUE)) == NULL)
288 ca = &dummy_attribute;
289 ca->value = a->value; /* Typically &Setting.xxx */
290 ca->type = CONFIG_Unused;
291 switch (a->type)
293 case HID_Boolean:
294 *(char *) a->value = a->default_val.int_value;
295 ca->type = CONFIG_Boolean;
296 break;
297 case HID_Integer:
298 *(int *) a->value = a->default_val.int_value;
299 ca->type = CONFIG_Integer;
300 break;
301 case HID_Coord:
302 *(Coord *) a->value = a->default_val.coord_value;
303 ca->type = CONFIG_Coord;
304 break;
305 case HID_Real:
306 *(double *) a->value = a->default_val.real_value;
307 ca->type = CONFIG_Real;
308 break;
310 case HID_String:
311 if (!a->name)
312 break;
313 *(char **) a->value = g_strdup (a->default_val.str_value);
314 ca->type = CONFIG_String;
316 len = strlen (a->name);
317 if (len < 7 || strstr (a->name, "color") == NULL)
318 break;
320 cc = g_new0 (ConfigColor, 1);
321 cc->attributes = a;
323 if (!strncmp (a->name, "layer-color", 11))
324 cc->type = LAYER_COLOR;
325 else if (!strncmp (a->name, "layer-selected-color", 20))
326 cc->type = LAYER_SELECTED_COLOR;
327 else if (!strncmp (a->name + len - 14, "selected-color", 14))
328 cc->type = MISC_SELECTED_COLOR;
329 else
330 cc->type = MISC_COLOR;
332 config_color_list = g_list_append (config_color_list, cc);
333 break;
335 case HID_Enum:
336 case HID_Unit:
337 *(int *) a->value = a->default_val.int_value;
338 break;
340 case HID_Label:
341 case HID_Mixed:
342 case HID_Path:
343 break;
344 default:
345 abort ();
351 static gint
352 parse_option_line (gchar * line, gchar ** option_result, gchar ** arg_result)
354 gchar *s, *ss, option[64], arg[512];
355 gint argc = 1;
357 if (option_result)
358 *option_result = NULL;
359 if (arg_result)
360 *arg_result = NULL;
362 s = line;
363 while (*s == ' ' || *s == '\t')
364 ++s;
365 if (!*s || *s == '\n' || *s == '#' || *s == '[')
366 return 0;
367 if ((ss = strchr (s, '\n')) != NULL)
368 *ss = '\0';
369 arg[0] = '\0';
370 sscanf (s, "%63s %511[^\n]", option, arg);
372 s = option; /* Strip trailing ':' or '=' */
373 while (*s && *s != ':' && *s != '=')
374 ++s;
375 *s = '\0';
377 s = arg; /* Strip leading ':', '=', and whitespace */
378 while (*s == ' ' || *s == '\t' || *s == ':' || *s == '=' || *s == '"')
379 ++s;
380 if ((ss = strchr (s, '"')) != NULL)
381 *ss = '\0';
383 if (option_result)
384 *option_result = g_strdup (option);
385 if (arg_result && *s)
387 *arg_result = g_strdup (s);
388 ++argc;
390 return argc;
393 static gboolean
394 set_config_attribute (gchar * option, gchar * arg)
396 ConfigAttribute *ca;
397 #if 0
398 struct lconv *lc;
399 gchar locale_point, *comma_point, *period_point;
401 /* Until LC_NUMERIC is totally resolved, check if we need to decimal
402 | point convert. Ultimately, data files will be POSIX and gui
403 | presentation (hence the config file reals) will be in the users locale.
405 lc = localeconv ();
406 locale_point = *lc->decimal_point;
407 #endif
409 if ((ca = lookup_config_attribute (option, FALSE)) == NULL)
410 return FALSE;
411 switch (ca->type)
413 case CONFIG_Boolean:
414 *(gchar *) ca->value = (gchar) atoi (arg);
415 break;
417 case CONFIG_Integer:
418 *(gint *) ca->value = atoi (arg);
419 break;
421 case CONFIG_Real:
422 /* Hopefully temporary locale decimal point check:
424 #if 0
425 comma_point = strrchr (arg, ',');
426 period_point = strrchr (arg, '.');
427 if (comma_point && *comma_point != locale_point)
428 *comma_point = locale_point;
429 else if (period_point && *period_point != locale_point)
430 *period_point = locale_point;
431 #endif
432 *(double *) ca->value = atof (arg);
433 break;
435 case CONFIG_String:
436 dup_string ((gchar **) ca->value, arg ? arg : (gchar *)"");
437 break;
438 case CONFIG_Coord:
439 *(Coord *) ca->value = GetValue (arg, NULL, NULL);
440 break;
441 default:
442 break;
444 return TRUE;
447 static void
448 config_file_read (void)
450 FILE *f;
451 gchar buf[512], *option, *arg;
453 if ((f = config_file_open ("r")) == NULL)
454 return;
456 buf[0] = '\0';
457 while (fgets (buf, sizeof (buf), f))
459 if (parse_option_line (buf, &option, &arg) > 0)
460 set_config_attribute (option, arg);
461 g_free (option);
462 g_free (arg);
465 fclose (f);
468 static void
469 config_colors_write (gchar * path)
471 FILE *f;
472 GList *list;
473 HID_Attribute *ha;
474 ConfigColor *cc;
476 if ((f = fopen (path, "w")) == NULL)
477 return;
478 for (list = config_color_list; list; list = list->next)
480 cc = (ConfigColor *) list->data;
481 ha = cc->attributes;
482 fprintf (f, "%s =\t%s\n", ha->name, *(char **) ha->value);
484 fclose (f);
487 static gboolean
488 config_colors_read (gchar * path)
490 FILE *f;
491 GList *list;
492 ConfigColor *cc;
493 HID_Attribute *ha;
494 gchar *s, buf[512], option[64], arg[512];
496 if (!path || !*path || (f = fopen (path, "r")) == NULL)
497 return FALSE;
499 while (fgets (buf, sizeof (buf), f))
501 sscanf (buf, "%63s %511[^\n]", option, arg);
502 s = option; /* Strip trailing ':' or '=' */
503 while (*s && *s != ':' && *s != '=')
504 ++s;
505 *s = '\0';
506 s = arg; /* Strip leading ':', '=', and whitespace */
507 while (*s == ' ' || *s == '\t' || *s == ':' || *s == '=')
508 ++s;
510 for (list = config_color_list; list; list = list->next)
512 cc = (ConfigColor *) list->data;
513 ha = cc->attributes;
514 if (!strcmp (option, ha->name))
516 *(char **) ha->value = g_strdup (s);
517 cc->color_is_mapped = FALSE;
518 ghid_set_special_colors (ha);
519 break;
523 fclose (f);
525 return TRUE;
528 static gchar *
529 expand_dir (gchar * dir)
531 gchar *s;
533 if (*dir == '~')
534 s = g_build_filename ((gchar *) g_get_home_dir (), dir + 1, NULL);
535 else
536 s = g_strdup (dir);
537 return s;
540 static void
541 add_to_paths_list (GList ** list, gchar * path_string)
543 gchar *p, *paths;
545 paths = g_strdup (path_string);
546 for (p = strtok (paths, PCB_PATH_DELIMETER); p && *p; p = strtok (NULL, PCB_PATH_DELIMETER))
547 *list = g_list_prepend (*list, expand_dir (p));
548 g_free (paths);
551 /* Parse command line code borrowed from hid/common/hidinit.c
553 static void
554 parse_optionv (gint * argc, gchar *** argv, gboolean from_cmd_line)
556 HID_AttrNode *ha;
557 HID_Attribute *a;
558 const Unit *unit;
559 gchar *ep;
560 gint e, ok, offset;
561 gboolean matched = FALSE;
563 offset = from_cmd_line ? 2 : 0;
565 while (*argc
566 && (((*argv)[0][0] == '-' && (*argv)[0][1] == '-')
567 || !from_cmd_line))
569 for (ha = hid_attr_nodes; ha; ha = ha->next)
571 for (a = ha->attributes; a < ha->attributes + ha->n; ++a)
573 if (!a->name || strcmp ((*argv)[0] + offset, a->name))
574 continue;
575 switch (a->type)
577 case HID_Label:
578 break;
579 case HID_Integer:
580 if (a->value)
581 *(int *) a->value = strtol ((*argv)[1], 0, 0);
582 else
583 a->default_val.int_value = strtol ((*argv)[1], 0, 0);
584 (*argc)--;
585 (*argv)++;
586 break;
587 case HID_Coord:
588 if (a->value)
589 *(Coord *) a->value = GetValue ((*argv)[1], 0, 0);
590 else
591 a->default_val.coord_value = GetValue ((*argv)[1], 0, 0);
592 (*argc)--;
593 (*argv)++;
594 break;
595 case HID_Real:
596 if (a->value)
597 *(double *) a->value = strtod ((*argv)[1], 0);
598 else
599 a->default_val.real_value = strtod ((*argv)[1], 0);
600 (*argc)--;
601 (*argv)++;
602 break;
603 case HID_String:
604 if (a->value)
605 *(char **) a->value = g_strdup((*argv)[1]);
606 else
607 a->default_val.str_value = g_strdup((*argv)[1]);
608 (*argc)--;
609 (*argv)++;
610 break;
611 case HID_Boolean:
612 if (a->value)
613 *(char *) a->value = 1;
614 else
615 a->default_val.int_value = 1;
616 break;
617 case HID_Mixed:
618 a->default_val.real_value = strtod ((*argv)[1], &ep);
619 goto do_enum;
620 case HID_Enum:
621 ep = (*argv)[1];
622 do_enum:
623 ok = 0;
624 for (e = 0; a->enumerations[e]; e++)
625 if (strcmp (a->enumerations[e], ep) == 0)
627 ok = 1;
628 a->default_val.int_value = e;
629 a->default_val.str_value = ep;
630 break;
632 if (!ok)
634 fprintf (stderr,
635 "ERROR: \"%s\" is an unknown value for the --%s option\n",
636 (*argv)[1], a->name);
637 exit (1);
639 (*argc)--;
640 (*argv)++;
641 break;
642 case HID_Path:
643 abort ();
644 a->default_val.str_value = (*argv)[1];
645 (*argc)--;
646 (*argv)++;
647 break;
648 case HID_Unit:
649 unit = get_unit_struct ((*argv)[1]);
650 if (unit == NULL)
652 fprintf (stderr,
653 "ERROR: unit \"%s\" is unknown to pcb (option --%s)\n",
654 (*argv)[1], a->name);
655 exit (1);
657 a->default_val.int_value = unit->index;
658 a->default_val.str_value = unit->suffix;
659 (*argc)--;
660 (*argv)++;
661 break;
663 (*argc)--;
664 (*argv)++;
665 ha = 0;
666 goto got_match;
668 if (a < ha->attributes + ha->n)
669 matched = TRUE;
671 if (!matched)
673 if (from_cmd_line)
675 fprintf (stderr, "unrecognized option: %s\n", (*argv)[0]);
676 exit (1);
678 else
679 // ghid_log("unrecognized option: %s\n", (*argv)[0]);
680 fprintf (stderr, "unrecognized option: %s\n", (*argv)[0]);
682 got_match:;
684 (*argc)++;
685 (*argv)--;
688 static void
689 load_rc_file (gchar * path)
691 FILE *f;
692 gchar buf[1024], *av[2], **argv;
693 gint argc;
695 f = fopen (path, "r");
696 if (!f)
697 return;
699 if (Settings.verbose)
700 printf ("Loading pcbrc file: %s\n", path);
701 while (fgets (buf, sizeof (buf), f))
703 argv = &(av[0]);
704 if ((argc = parse_option_line (buf, &av[0], &av[1])) > 0)
705 parse_optionv (&argc, &argv, FALSE);
706 g_free (av[0]);
707 g_free (av[1]);
709 fclose (f);
712 static void
713 load_rc_files (void)
715 gchar *path;
717 load_rc_file ("/etc/pcbrc");
718 load_rc_file ("/usr/local/etc/pcbrc");
720 path = g_build_filename (pcblibdir, "pcbrc", NULL);
721 load_rc_file (path);
722 g_free (path);
724 path = g_build_filename ((gchar *) g_get_home_dir (), ".pcb/pcbrc", NULL);
725 load_rc_file (path);
726 g_free (path);
728 load_rc_file ("pcbrc");
732 void
733 ghid_config_files_read (gint * argc, gchar *** argv)
735 GList *list;
736 gchar *str, *dir;
737 gint width, height;
739 ghidgui = &_ghidgui;
741 ghid_config_init ();
742 load_rc_files ();
743 config_file_read ();
744 config_colors_read (color_file);
745 (*argc)--;
746 (*argv)++;
747 parse_optionv (argc, argv, TRUE);
749 if (board_size_override
750 && sscanf (board_size_override, "%dx%d", &width, &height) == 2)
752 Settings.MaxWidth = TO_PCB_UNITS (width);
753 Settings.MaxHeight = TO_PCB_UNITS (height);
756 if (lib_newlib_config && *lib_newlib_config)
757 add_to_paths_list (&lib_newlib_list, lib_newlib_config);
759 for (list = lib_newlib_list; list; list = list->next)
761 str = Settings.LibraryTree;
762 dir = expand_dir ((gchar *) list->data);
763 Settings.LibraryTree = g_strconcat (str, PCB_PATH_DELIMETER, dir, NULL);
764 g_free (dir);
765 g_free (str);
769 void
770 ghid_config_files_write (void)
772 FILE *f;
773 ConfigAttribute *ca;
775 if (!ghidgui->config_modified || (f = config_file_open ("w")) == NULL)
776 return;
778 fprintf (f, "### PCB configuration file. ###\n");
780 for (ca = &config_attributes[0];
781 ca < &config_attributes[0] + G_N_ELEMENTS (config_attributes); ++ca)
783 switch (ca->type)
785 case CONFIG_Boolean:
786 fprintf (f, "%s = %d\n", ca->name, (gint) * (gchar *) ca->value);
787 break;
789 case CONFIG_Integer:
790 fprintf (f, "%s = %d\n", ca->name, *(gint *) ca->value);
791 break;
793 case CONFIG_Real:
794 fprintf (f, "%s = %f\n", ca->name, *(double *) ca->value);
795 break;
797 case CONFIG_Coord:
798 pcb_fprintf (f, "%s = %$mS\n", ca->name, *(Coord *) ca->value);
799 break;
801 case CONFIG_String:
802 if (*(char **) ca->value == NULL)
803 fprintf (f, "# %s = NULL\n", ca->name);
804 else
805 fprintf (f, "%s = %s\n", ca->name, *(char **) ca->value);
806 break;
807 default:
808 break;
811 fclose (f);
813 ghidgui->config_modified = FALSE;
816 /* =================== OK, now the gui stuff ======================
818 static GtkWidget *config_window;
820 /* -------------- The General config page ----------------
823 static void
824 config_command_window_toggle_cb (GtkToggleButton * button, gpointer data)
826 gboolean active = gtk_toggle_button_get_active (button);
827 static gboolean holdoff;
829 if (holdoff)
830 return;
832 /* Can't toggle into command window mode if the status line command
833 | entry is active.
835 if (ghidgui->command_entry_status_line_active)
837 holdoff = TRUE;
838 gtk_toggle_button_set_active (button, FALSE);
839 holdoff = FALSE;
840 return;
842 ghidgui->use_command_window = active;
843 ghid_command_use_command_window_sync ();
847 static void
848 config_compact_horizontal_toggle_cb (GtkToggleButton * button, gpointer data)
850 gboolean active = gtk_toggle_button_get_active (button);
852 ghidgui->compact_horizontal = active;
853 ghid_set_status_line_label ();
854 ghidgui->config_modified = TRUE;
857 static void
858 config_compact_vertical_toggle_cb (GtkToggleButton * button, gpointer data)
860 gboolean active = gtk_toggle_button_get_active (button);
862 ghidgui->compact_vertical = active;
863 ghid_pack_mode_buttons();
864 ghidgui->config_modified = TRUE;
867 static void
868 config_general_toggle_cb (GtkToggleButton * button, void * setting)
870 *(gint *)setting = gtk_toggle_button_get_active (button);
871 ghidgui->config_modified = TRUE;
874 static void
875 config_backup_spin_button_cb (GtkSpinButton * spin_button, gpointer data)
877 Settings.BackupInterval = gtk_spin_button_get_value_as_int (spin_button);
878 EnableAutosave ();
879 ghidgui->config_modified = TRUE;
882 static void
883 config_history_spin_button_cb (GtkSpinButton * spin_button, gpointer data)
885 ghidgui->history_size = gtk_spin_button_get_value_as_int (spin_button);
886 ghidgui->config_modified = TRUE;
889 static void
890 config_general_tab_create (GtkWidget * tab_vbox)
892 GtkWidget *vbox;
894 gtk_container_set_border_width (GTK_CONTAINER (tab_vbox), 6);
896 vbox = ghid_category_vbox (tab_vbox, _("Enables"), 4, 2, TRUE, TRUE);
898 ghid_check_button_connected (vbox, NULL, ghidgui->use_command_window,
899 TRUE, FALSE, FALSE, 2,
900 config_command_window_toggle_cb, NULL,
901 _("Use separate window for command entry"));
903 ghid_check_button_connected (vbox, NULL, ghidgui->compact_horizontal,
904 TRUE, FALSE, FALSE, 2,
905 config_compact_horizontal_toggle_cb, NULL,
906 _("Alternate window layout to allow smaller horizontal size"));
908 ghid_check_button_connected (vbox, NULL, ghidgui->compact_vertical,
909 TRUE, FALSE, FALSE, 2,
910 config_compact_vertical_toggle_cb, NULL,
911 _("Alternate window layout to allow smaller vertical size"));
913 vbox = ghid_category_vbox (tab_vbox, _("Backups"), 4, 2, TRUE, TRUE);
914 ghid_check_button_connected (vbox, NULL, Settings.SaveInTMP,
915 TRUE, FALSE, FALSE, 2,
916 config_general_toggle_cb, &Settings.SaveInTMP,
917 _("If layout is modified at exit, save into PCB.%i.save"));
918 ghid_spin_button (vbox, NULL, Settings.BackupInterval, 0.0, 60 * 60, 60.0,
919 600.0, 0, 0, config_backup_spin_button_cb, NULL, FALSE,
920 _("Seconds between auto backups\n"
921 "(set to zero to disable auto backups)"));
923 vbox = ghid_category_vbox (tab_vbox, _("Misc"), 4, 2, TRUE, TRUE);
924 ghid_spin_button (vbox, NULL, ghidgui->history_size,
925 5.0, 25.0, 1.0, 1.0, 0, 0,
926 config_history_spin_button_cb, NULL, FALSE,
927 _("Number of commands to remember in the history list"));
931 static void
932 config_general_apply (void)
934 /* save the settings */
935 ghid_config_files_write ();
939 /* -------------- The Sizes config page ----------------
942 static GtkWidget *config_sizes_vbox,
943 *config_sizes_tab_vbox, *config_text_spin_button;
945 static GtkWidget *use_board_size_default_button,
946 *use_drc_sizes_default_button,
947 *use_increments_default_button;
949 static Coord new_board_width, new_board_height;
951 static void
952 config_sizes_apply (void)
954 gboolean active;
956 active =
957 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
958 (use_board_size_default_button));
959 if (active)
961 Settings.MaxWidth = new_board_width;
962 Settings.MaxHeight = new_board_height;
963 ghidgui->config_modified = TRUE;
966 active =
967 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
968 (use_drc_sizes_default_button));
969 if (active)
971 Settings.Bloat = PCB->Bloat;
972 Settings.Shrink = PCB->Shrink;
973 Settings.minWid = PCB->minWid;
974 Settings.minSlk = PCB->minSlk;
975 Settings.IsleArea = PCB->IsleArea;
976 Settings.minDrill = PCB->minDrill;
977 Settings.minRing = PCB->minRing;
978 ghidgui->config_modified = TRUE;
981 active =
982 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
983 (use_increments_default_button));
984 if (active)
986 save_increments (get_increments_struct (METRIC),
987 get_increments_struct (IMPERIAL));
988 ghidgui->config_modified = TRUE;
991 if (PCB->MaxWidth != new_board_width || PCB->MaxHeight != new_board_height)
992 ChangePCBSize (new_board_width, new_board_height);
995 static void
996 text_spin_button_cb (GtkSpinButton * spin, void * dst)
998 *(gint *)dst = gtk_spin_button_get_value_as_int (spin);
999 ghidgui->config_modified = TRUE;
1000 ghid_set_status_line_label ();
1003 static void
1004 coord_entry_cb (GHidCoordEntry * ce, void * dst)
1006 *(Coord *) dst = ghid_coord_entry_get_value (ce);
1007 ghidgui->config_modified = TRUE;
1010 static void
1011 config_sizes_tab_create (GtkWidget * tab_vbox)
1013 GtkWidget *table, *vbox, *hbox;
1015 /* Need a vbox we can destroy if user changes grid units.
1017 if (!config_sizes_vbox)
1019 vbox = gtk_vbox_new (FALSE, 0);
1020 gtk_box_pack_start (GTK_BOX (tab_vbox), vbox, FALSE, FALSE, 0);
1021 gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
1022 config_sizes_vbox = vbox;
1023 config_sizes_tab_vbox = tab_vbox;
1026 /* ---- Board Size ---- */
1027 vbox = ghid_category_vbox (config_sizes_vbox, _("Board Size"),
1028 4, 2, TRUE, TRUE);
1029 hbox = gtk_hbox_new (FALSE, 0);
1030 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1031 table = gtk_table_new (2, 2, FALSE);
1032 gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
1033 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1034 gtk_table_set_row_spacings (GTK_TABLE (table), 3);
1036 new_board_width = PCB->MaxWidth;
1037 new_board_height = PCB->MaxHeight;
1038 ghid_table_coord_entry (table, 0, 0, NULL,
1039 PCB->MaxWidth, MIN_SIZE, MAX_COORD,
1040 CE_LARGE, 0, coord_entry_cb,
1041 &new_board_width, FALSE, _("Width"));
1043 ghid_table_coord_entry (table, 1, 0, NULL,
1044 PCB->MaxHeight, MIN_SIZE, MAX_COORD,
1045 CE_LARGE, 0, coord_entry_cb,
1046 &new_board_height, FALSE, _("Height"));
1047 ghid_check_button_connected (vbox, &use_board_size_default_button, FALSE,
1048 TRUE, FALSE, FALSE, 0, NULL, NULL,
1049 _("Use this board size as the default for new layouts"));
1051 /* ---- Text Scale ---- */
1052 vbox = ghid_category_vbox (config_sizes_vbox, _("Text Scale"),
1053 4, 2, TRUE, TRUE);
1054 hbox = gtk_hbox_new (FALSE, 0);
1055 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1056 table = gtk_table_new (4, 2, FALSE);
1057 gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
1058 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1059 gtk_table_set_row_spacings (GTK_TABLE (table), 3);
1061 ghid_table_spin_button (table, 0, 0, &config_text_spin_button,
1062 Settings.TextScale,
1063 MIN_TEXTSCALE, MAX_TEXTSCALE,
1064 10.0, 10.0,
1065 0, 0, text_spin_button_cb,
1066 &Settings.TextScale, FALSE, "%");
1069 /* ---- DRC Sizes ---- */
1070 vbox = ghid_category_vbox (config_sizes_vbox, _("Design Rule Checking"),
1071 4, 2, TRUE, TRUE);
1072 hbox = gtk_hbox_new (FALSE, 0);
1073 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1074 table = gtk_table_new (4, 2, FALSE);
1075 gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
1076 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1077 gtk_table_set_row_spacings (GTK_TABLE (table), 3);
1079 ghid_table_coord_entry (table, 0, 0, NULL,
1080 PCB->Bloat, MIN_DRC_VALUE, MAX_DRC_VALUE,
1081 CE_SMALL, 0, coord_entry_cb,
1082 &PCB->Bloat, FALSE,
1083 _("Minimum copper spacing"));
1085 ghid_table_coord_entry (table, 1, 0, NULL,
1086 PCB->minWid, MIN_DRC_VALUE, MAX_DRC_VALUE,
1087 CE_SMALL, 0, coord_entry_cb,
1088 &PCB->minWid, FALSE,
1089 _("Minimum copper width"));
1091 ghid_table_coord_entry (table, 2, 0, NULL,
1092 PCB->Shrink, MIN_DRC_VALUE, MAX_DRC_VALUE,
1093 CE_SMALL, 0, coord_entry_cb,
1094 &PCB->Shrink, FALSE,
1095 _("Minimum touching copper overlap"));
1097 ghid_table_coord_entry (table, 3, 0, NULL,
1098 PCB->minSlk, MIN_DRC_VALUE, MAX_DRC_VALUE,
1099 CE_SMALL, 0, coord_entry_cb,
1100 &PCB->minSlk, FALSE,
1101 _("Minimum silk width"));
1103 ghid_table_coord_entry (table, 4, 0, NULL,
1104 PCB->minDrill, MIN_DRC_VALUE, MAX_DRC_VALUE,
1105 CE_SMALL, 0, coord_entry_cb,
1106 &PCB->minDrill, FALSE,
1107 _("Minimum drill diameter"));
1109 ghid_table_coord_entry (table, 5, 0, NULL,
1110 PCB->minRing, MIN_DRC_VALUE, MAX_DRC_VALUE,
1111 CE_SMALL, 0, coord_entry_cb,
1112 &PCB->minRing, FALSE,
1113 _("Minimum annular ring"));
1115 ghid_check_button_connected (vbox, &use_drc_sizes_default_button, FALSE,
1116 TRUE, FALSE, FALSE, 0, NULL, NULL,
1118 ("Use DRC values as the default for new layouts"));
1120 gtk_widget_show_all (config_sizes_vbox);
1124 /* -------------- The Increments config page ----------------
1126 /* Increment/decrement values are kept in mil and mm units and not in
1127 | PCB units.
1129 static GtkWidget *config_increments_vbox, *config_increments_tab_vbox;
1131 static void
1132 increment_spin_button_cb (GHidCoordEntry * ce, void * dst)
1134 *(Coord *)dst = ghid_coord_entry_get_value (ce);
1135 ghidgui->config_modified = TRUE;
1138 static void
1139 config_increments_tab_create (GtkWidget * tab_vbox)
1141 Increments *incr_mm = get_increments_struct (METRIC);
1142 Increments *incr_mil = get_increments_struct (IMPERIAL);
1143 GtkWidget *vbox, *hbox, *table;
1145 /* Need a vbox we can destroy if user changes grid units.
1147 if (!config_increments_vbox)
1149 vbox = gtk_vbox_new (FALSE, 0);
1150 gtk_box_pack_start (GTK_BOX (tab_vbox), vbox, FALSE, FALSE, 0);
1151 gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
1152 config_increments_vbox = vbox;
1153 config_increments_tab_vbox = tab_vbox;
1156 #define INCR_ENTRY(row, name, family, type, msg) \
1157 gtk_table_attach_defaults (GTK_TABLE (table), \
1158 gtk_label_new (name), \
1159 0, 1, row, row + 1); \
1160 ghid_table_coord_entry (table, row, 1, NULL, \
1161 incr_##family->type, \
1162 incr_##family->type##_min, \
1163 incr_##family->type##_max, \
1164 CE_SMALL, 0, increment_spin_button_cb, \
1165 &incr_##family->type, FALSE, \
1166 msg)
1168 /* ---- Metric Settings ---- */
1169 vbox = ghid_category_vbox (config_increments_vbox,
1170 _("Metric Increment Settings"), 4, 2, TRUE, TRUE);
1171 hbox = gtk_hbox_new (FALSE, 0);
1172 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1173 table = gtk_table_new (4, 3, FALSE);
1174 gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
1175 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1176 gtk_table_set_row_spacings (GTK_TABLE (table), 18);
1178 INCR_ENTRY (0, _("Grid:"), mm, grid,
1179 _("For 'g' and '<shift>g' grid change actions"));
1180 INCR_ENTRY (1, _("Size:"), mm, size,
1181 _("For 's' and '<shift>s' size change actions on lines,\n"
1182 "pads, pins and text.\n"
1183 "Use '<ctrl>s' and '<shift><ctrl>s' for drill holes."));
1184 INCR_ENTRY (2, _("Line:"), mm, line,
1185 _("For 'l' and '<shift>l' routing line width change actions"));
1186 INCR_ENTRY (3, _("Clear:"), mm, clear,
1187 _("For 'k' and '<shift>k' line clearance inside polygon size\n"
1188 "change actions"));
1190 vbox = ghid_category_vbox (config_increments_vbox,
1191 _("Imperial Increment Settings"), 4, 2, TRUE, TRUE);
1192 hbox = gtk_hbox_new (FALSE, 0);
1193 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1194 table = gtk_table_new (4, 3, FALSE);
1195 gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
1196 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1197 gtk_table_set_row_spacings (GTK_TABLE (table), 18);
1199 INCR_ENTRY (0, _("Grid:"), mil, grid,
1200 _("For 'g' and '<shift>g' grid change actions"));
1201 INCR_ENTRY (1, _("Size:"), mil, size,
1202 _("For 's' and '<shift>s' size change actions on lines,\n"
1203 "pads, pins and text.\n"
1204 "Use '<ctrl>s' and '<shift><ctrl>s' for drill holes."));
1205 INCR_ENTRY (2, _("Line:"), mil, line,
1206 _("For 'l' and '<shift>l' routing line width change actions"));
1207 INCR_ENTRY (3, _("Clear:"), mil, clear,
1208 _("For 'k' and '<shift>k' line clearance inside polygon size\n"
1209 "change actions"));
1210 #undef INCR_ENTRY
1212 vbox = ghid_category_vbox (config_increments_vbox,
1213 _("Save as Default"), 4, 2, TRUE, TRUE);
1214 ghid_check_button_connected (vbox, &use_increments_default_button, FALSE,
1215 TRUE, FALSE, FALSE, 0, NULL, NULL,
1216 _("Use values as the default for new layouts"));
1218 gtk_widget_show_all (config_increments_vbox);
1221 /* -------------- The Library config page ----------------
1223 static GtkWidget *library_newlib_entry;
1225 static void
1226 config_library_apply (void)
1228 if (dup_string
1229 (&lib_newlib_config, ghid_entry_get_text (library_newlib_entry)))
1230 ghidgui->config_modified = TRUE;
1233 static void
1234 config_library_tab_create (GtkWidget * tab_vbox)
1236 GtkWidget *vbox, *label, *entry;
1238 gtk_container_set_border_width (GTK_CONTAINER (tab_vbox), 6);
1239 vbox = ghid_category_vbox (tab_vbox, _("Element Directories"),
1240 4, 2, TRUE, TRUE);
1241 label = gtk_label_new ("");
1242 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
1243 gtk_label_set_markup (GTK_LABEL (label),
1245 ("<small>Enter a \""
1246 PCB_PATH_DELIMETER
1247 "\" separated list of custom top level\n"
1248 "element directories. For example:\n"
1249 "\t<b>~/gaf/pcb-elements"
1250 PCB_PATH_DELIMETER
1251 "packages"
1252 PCB_PATH_DELIMETER
1253 "/usr/local/pcb-elements</b>\n"
1254 "Elements should be organized into subdirectories below each\n"
1255 "top level directory. Restart program for changes to take effect."
1256 "</small>"));
1258 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
1259 entry = gtk_entry_new ();
1260 library_newlib_entry = entry;
1261 gtk_entry_set_text (GTK_ENTRY (entry), lib_newlib_config);
1262 gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 4);
1266 /* -------------- The Layers Group config page ----------------
1268 static GtkWidget *config_groups_table, *config_groups_vbox, *config_groups_window;
1270 static GtkWidget *layer_entry[MAX_LAYER];
1271 static GtkWidget *group_button[MAX_LAYER + 2][MAX_LAYER];
1273 #if FIXME
1274 static GtkWidget *use_layer_default_button;
1275 #endif
1277 static gint config_layer_group[MAX_LAYER + 2];
1279 static LayerGroupType layer_groups, /* Working copy */
1280 *lg_monitor; /* Keep track if our working copy */
1281 /* needs to be changed (new layout) */
1283 static gboolean groups_modified, groups_holdoff, layers_applying;
1285 static gchar *layer_info_text[] = {
1286 N_("<h>Layer Names\n"),
1287 N_("You may enter layer names for the layers drawn on the screen.\n"
1288 "The special 'top side' and 'bottom side' are layers which\n"
1289 "will be printed out, so they must have in their group at least one\n"
1290 "of the other layers that are drawn on the screen.\n"),
1291 "\n",
1292 N_("<h>Layer Groups\n"),
1293 N_("Each layer on the screen may be in its own group which allows the\n"
1294 "maximum number of board layers. However, for boards with fewer\n"
1295 "layers, you may group layers together which will then print as a\n"
1296 "single layer on a printout. This allows a visual color distinction\n"
1297 "to be displayed on the screen for signal groups which will print as\n"
1298 "a single layer\n"),
1299 "\n",
1300 N_("For example, for a 4 layer board a useful layer group arrangement\n"
1301 "can be to have 3 screen displayed layers grouped into the same group\n"
1302 "as the 'top side' and 'bottom side' printout layers. Then\n"
1303 "groups such as signals, ground, and supply traces can be color\n"
1304 "coded on the screen while printing as a single layer. For this\n"
1305 "you would select buttons and enter names on the Setup page to\n"
1306 "structure four layer groups similar to this:\n"),
1307 "\n",
1308 N_("<b>Group 1:"),
1309 "\n\t",
1310 N_("top"),
1311 "\n\t",
1312 N_("GND-top"),
1313 "\n\t",
1314 N_("Vcc-top"),
1315 "\n\t",
1316 N_("top side"),
1317 "\n",
1318 N_("<b>Group 2:"),
1319 "\n\t",
1320 N_("bottom"),
1321 "\n\t",
1322 N_("GND-bottom"),
1323 "\n\t",
1324 N_("Vcc-bottom"),
1325 "\n\t",
1326 N_("bottom side"),
1327 "\n",
1328 N_("<b>Group 3:"),
1329 "\n\t",
1330 N_("signal1"),
1331 "\n",
1332 N_("<b>Group 4:"),
1333 "\n\t",
1334 N_("signal2"),
1335 "\n"
1338 static void
1339 config_layer_groups_radio_button_cb (GtkToggleButton * button, gpointer data)
1341 gint layer = GPOINTER_TO_INT (data) >> 8;
1342 gint group = GPOINTER_TO_INT (data) & 0xff;
1344 if (!gtk_toggle_button_get_active (button) || groups_holdoff)
1345 return;
1346 config_layer_group[layer] = group;
1347 groups_modified = TRUE;
1348 ghidgui->config_modified = TRUE;
1351 /* Construct a layer group string. Follow logic in WritePCBDataHeader(),
1352 | but use g_string functions.
1354 static gchar *
1355 make_layer_group_string (LayerGroupType * lg)
1357 GString *string;
1358 gint group, entry, layer;
1360 string = g_string_new ("");
1362 for (group = 0; group < max_group; group++)
1364 if (lg->Number[group] == 0)
1365 continue;
1366 for (entry = 0; entry < lg->Number[group]; entry++)
1368 layer = lg->Entries[group][entry];
1369 if (layer == component_silk_layer)
1370 string = g_string_append (string, "c");
1371 else if (layer == solder_silk_layer)
1372 string = g_string_append (string, "s");
1373 else
1374 g_string_append_printf (string, "%d", layer + 1);
1376 if (entry != lg->Number[group] - 1)
1377 string = g_string_append (string, ",");
1379 if (group != max_group - 1)
1380 string = g_string_append (string, ":");
1382 return g_string_free (string, FALSE); /* Don't free string->str */
1385 static void
1386 config_layers_apply (void)
1388 LayerType *layer;
1389 gchar *s;
1390 gint group, i;
1391 gint componentgroup = 0, soldergroup = 0;
1392 gboolean use_as_default = FALSE, layers_modified = FALSE;
1394 #if FIXME
1395 use_as_default =
1396 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
1397 (use_layer_default_button));
1398 #endif
1400 /* Get each layer name entry and dup if modified into the PCB layer names
1401 | and, if to use as default, the Settings layer names.
1403 for (i = 0; i < max_copper_layer; ++i)
1405 layer = &PCB->Data->Layer[i];
1406 s = ghid_entry_get_text (layer_entry[i]);
1407 if (dup_core_string (&layer->Name, s))
1408 layers_modified = TRUE;
1409 /* FIXME */
1410 if (use_as_default && dup_core_string (&Settings.DefaultLayerName[i], s))
1411 ghidgui->config_modified = TRUE;
1414 /* Layer names can be changed from the menus and that can update the
1415 | config. So holdoff the loop.
1417 layers_applying = TRUE;
1418 if (layers_modified)
1419 ghid_layer_buttons_update ();
1420 layers_applying = FALSE;
1422 if (groups_modified) /* If any group radio buttons were toggled. */
1424 /* clear all entries and read layer by layer
1426 for (group = 0; group < max_group; group++)
1427 layer_groups.Number[group] = 0;
1429 for (i = 0; i < max_copper_layer + 2; i++)
1431 group = config_layer_group[i] - 1;
1432 layer_groups.Entries[group][layer_groups.Number[group]++] = i;
1434 if (i == component_silk_layer)
1435 componentgroup = group;
1436 else if (i == solder_silk_layer)
1437 soldergroup = group;
1440 /* do some cross-checking
1441 | top-side and bottom-side must be in different groups
1442 | top-side and bottom-side must not be the only one in the group
1444 if (layer_groups.Number[soldergroup] <= 1
1445 || layer_groups.Number[componentgroup] <= 1)
1447 Message (_
1448 ("Both, 'top side' and 'bottom side' layer must have at least\n"
1449 "\tone other layer in their group.\n"));
1450 return;
1452 else if (soldergroup == componentgroup)
1454 Message (_
1455 ("The 'top side' and 'bottom side' layers are not allowed\n"
1456 "\tto be in the same layer group #\n"));
1457 return;
1459 PCB->LayerGroups = layer_groups;
1460 ghid_invalidate_all();
1461 groups_modified = FALSE;
1463 if (use_as_default)
1465 s = make_layer_group_string (&PCB->LayerGroups);
1466 if (dup_core_string (&Settings.Groups, s))
1468 ParseGroupString (Settings.Groups, &Settings.LayerGroups, max_copper_layer);
1469 ghidgui->config_modified = TRUE;
1471 g_free (s);
1475 static void
1476 config_layer_group_button_state_update (void)
1478 gint g, i;
1480 /* Set button active corresponding to layer group state.
1482 groups_holdoff = TRUE;
1483 for (g = 0; g < max_group; g++)
1484 for (i = 0; i < layer_groups.Number[g]; i++)
1486 /* printf("layer %d in group %d\n", layer_groups.Entries[g][i], g +1); */
1487 config_layer_group[layer_groups.Entries[g][i]] = g + 1;
1488 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
1489 (group_button
1490 [layer_groups.Entries[g][i]][g]),
1491 TRUE);
1493 groups_holdoff = FALSE;
1496 static void
1497 layer_name_entry_cb(GtkWidget *entry, gpointer data)
1499 gint i = GPOINTER_TO_INT(data);
1500 LayerType *layer;
1501 gchar *name;
1503 layer = &PCB->Data->Layer[i];
1504 name = ghid_entry_get_text(entry);
1505 if (dup_core_string (&layer->Name, name))
1506 ghid_layer_buttons_update();
1509 void
1510 ghid_config_groups_changed(void)
1512 GtkWidget *vbox, *table, *button, *label, *scrolled_window;
1513 GSList *group;
1514 gchar buf[32], *name;
1515 gint layer, i;
1517 if (!config_groups_vbox)
1518 return;
1519 vbox = config_groups_vbox;
1521 if (config_groups_table)
1522 gtk_widget_destroy(config_groups_table);
1523 if (config_groups_window)
1524 gtk_widget_destroy(config_groups_window);
1526 config_groups_window = scrolled_window =
1527 gtk_scrolled_window_new (NULL, NULL);
1528 gtk_widget_set_size_request (scrolled_window, 34, 408);
1529 gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 3);
1530 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
1531 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1532 gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
1533 gtk_widget_show (scrolled_window);
1536 table = gtk_table_new (max_copper_layer + 3, max_group + 1, FALSE);
1537 config_groups_table = table;
1538 gtk_table_set_row_spacings (GTK_TABLE (table), 3);
1539 gtk_scrolled_window_add_with_viewport (
1540 GTK_SCROLLED_WINDOW (scrolled_window), table);
1541 gtk_widget_show (table);
1543 layer_groups = PCB->LayerGroups; /* working copy */
1544 lg_monitor = &PCB->LayerGroups; /* So can know if PCB changes on us */
1546 label = gtk_label_new (_("Group #"));
1547 gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1);
1548 gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
1550 for (i = 1; i < max_group + 1; ++i)
1552 if (i < 10)
1553 snprintf (buf, sizeof (buf), " %d", i);
1554 else
1555 snprintf (buf, sizeof (buf), "%d", i);
1556 label = gtk_label_new (buf);
1557 gtk_table_attach_defaults (GTK_TABLE (table), label, i, i + 1, 0, 1);
1560 /* Create a row of radio toggle buttons for layer. So each layer
1561 | can have an active radio button set for the group it needs to be in.
1563 for (layer = 0; layer < max_copper_layer + 2; ++layer)
1565 if (layer == component_silk_layer)
1566 name = _("top side");
1567 else if (layer == solder_silk_layer)
1568 name = _("bottom side");
1569 else
1570 name = (gchar *) UNKNOWN (PCB->Data->Layer[layer].Name);
1572 if (layer >= max_copper_layer)
1574 label = gtk_label_new (name);
1575 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1576 gtk_table_attach_defaults (GTK_TABLE (table), label,
1577 0, 1, layer + 1, layer + 2);
1579 else
1581 layer_entry[layer] = gtk_entry_new ();
1582 gtk_entry_set_text (GTK_ENTRY (layer_entry[layer]), name);
1583 gtk_table_attach_defaults (GTK_TABLE (table), layer_entry[layer],
1584 0, 1, layer + 1, layer + 2);
1585 g_signal_connect(G_OBJECT(layer_entry[layer]), "activate",
1586 G_CALLBACK(layer_name_entry_cb), GINT_TO_POINTER(layer));
1589 group = NULL;
1590 for (i = 0; i < max_group; ++i)
1592 snprintf (buf, sizeof (buf), "%2.2d", i+1);
1593 button = gtk_radio_button_new_with_label (group, buf);
1595 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE);
1596 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
1597 gtk_table_attach_defaults (GTK_TABLE (table), button,
1598 i + 1, i + 2, layer + 1, layer + 2);
1599 g_signal_connect (G_OBJECT (button), "toggled",
1600 G_CALLBACK (config_layer_groups_radio_button_cb),
1601 GINT_TO_POINTER ((layer << 8) | (i + 1)));
1602 group_button[layer][i] = button;
1605 gtk_widget_show_all(config_groups_vbox);
1606 config_layer_group_button_state_update ();
1610 static void
1611 edit_layer_button_cb(GtkWidget *widget, gchar *data)
1613 gchar **argv;
1615 if (PCB->RatDraw || PCB->SilkActive)
1616 return;
1618 argv = g_strsplit(data, ",", -1);
1619 MoveLayerAction(2, argv, 0, 0);
1620 g_strfreev(argv);
1623 static void
1624 config_layers_tab_create (GtkWidget * tab_vbox)
1626 GtkWidget *tabs, *vbox, *vbox1, *button, *text, *sep;
1627 GtkWidget *hbox, *arrow;
1628 gint i;
1630 tabs = gtk_notebook_new ();
1631 gtk_box_pack_start (GTK_BOX (tab_vbox), tabs, TRUE, TRUE, 0);
1633 /* -- Change tab */
1634 vbox = ghid_notebook_page(tabs, _("Change"), 0, 6);
1635 vbox1 = ghid_category_vbox(vbox,
1636 _("Operations on currently selected layer:"),
1637 4, 2, TRUE, TRUE);
1639 button = gtk_button_new();
1640 arrow = gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_ETCHED_IN);
1641 gtk_container_add(GTK_CONTAINER(button), arrow);
1642 g_signal_connect(G_OBJECT(button), (gchar *)"clicked",
1643 G_CALLBACK(edit_layer_button_cb), (gchar *)"c,up");
1644 hbox = gtk_hbox_new(FALSE, 0);
1645 gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
1646 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1648 button = gtk_button_new();
1649 arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_ETCHED_IN);
1650 gtk_container_add(GTK_CONTAINER(button), arrow);
1651 g_signal_connect(G_OBJECT(button), (gchar *)"clicked",
1652 G_CALLBACK(edit_layer_button_cb), (gchar *)"c,down");
1653 hbox = gtk_hbox_new(FALSE, 0);
1654 gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
1655 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1657 button = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1658 g_signal_connect(G_OBJECT(button), (gchar *)"clicked",
1659 G_CALLBACK(edit_layer_button_cb), (gchar *)"c,-1");
1660 hbox = gtk_hbox_new(FALSE, 0);
1661 gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
1662 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1664 vbox1 = ghid_category_vbox(vbox,
1665 _("Add new layer above currently selected layer:"),
1666 4, 2, TRUE, TRUE);
1667 button = gtk_button_new_from_stock(GTK_STOCK_ADD);
1668 g_signal_connect(G_OBJECT(button), (gchar *)"clicked",
1669 G_CALLBACK(edit_layer_button_cb), (gchar *)"-1,c");
1670 hbox = gtk_hbox_new(FALSE, 0);
1671 gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
1672 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1674 /* -- Groups tab */
1675 vbox = ghid_notebook_page (tabs, _("Groups"), 0, 6);
1676 config_groups_vbox = gtk_vbox_new(FALSE, 0);
1677 gtk_box_pack_start(GTK_BOX(vbox), config_groups_vbox, FALSE, FALSE, 0);
1678 ghid_config_groups_changed();
1680 sep = gtk_hseparator_new ();
1681 gtk_box_pack_start (GTK_BOX (vbox), sep, FALSE, FALSE, 4);
1683 #if FIXME
1684 ghid_check_button_connected (vbox, &use_layer_default_button, FALSE,
1685 TRUE, FALSE, FALSE, 8, NULL, NULL,
1686 ("Use these layer settings as the default for new layouts"));
1687 #endif
1690 /* -- Info tab */
1691 vbox = ghid_notebook_page (tabs, _("Info"), 0, 6);
1693 text = ghid_scrolled_text_view (vbox, NULL,
1694 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1695 for (i = 0; i < sizeof (layer_info_text) / sizeof (gchar *); ++i)
1696 ghid_text_view_append (text, _(layer_info_text[i]));
1700 void
1701 ghid_config_layer_name_update (gchar * name, gint layer)
1703 if (!config_window || layers_applying || !name)
1704 return;
1705 gtk_entry_set_text (GTK_ENTRY (layer_entry[layer]), name);
1707 /* If we get a config layer name change because a new PCB is loaded
1708 | or new layout started, need to change our working layer group copy.
1710 if (lg_monitor != &PCB->LayerGroups)
1712 layer_groups = PCB->LayerGroups;
1713 lg_monitor = &PCB->LayerGroups;
1714 config_layer_group_button_state_update ();
1715 groups_modified = FALSE;
1719 /* -------------- The Colors config page ----------------
1721 static GtkWidget *config_colors_vbox,
1722 *config_colors_tab_vbox,
1723 *config_colors_save_button,
1724 *config_color_file_label, *config_color_warn_label;
1726 static void config_colors_tab_create (GtkWidget * tab_vbox);
1728 static gboolean config_colors_modified;
1730 static void
1731 config_color_file_set_label (void)
1733 gchar *str, *name;
1735 if (!*color_file)
1736 name = g_strdup ("defaults");
1737 else
1738 name = g_path_get_basename (color_file);
1740 str = g_strdup_printf (_("Current colors loaded: <b>%s</b>"), name);
1741 gtk_label_set_markup (GTK_LABEL (config_color_file_label), str);
1742 g_free (name);
1743 g_free (str);
1746 static void
1747 config_color_defaults_cb (gpointer data)
1749 GList *list;
1750 ConfigColor *cc;
1751 HID_Attribute *ha;
1753 for (list = config_color_list; list; list = list->next)
1755 cc = (ConfigColor *) list->data;
1756 ha = cc->attributes;
1757 dup_core_string ((char **) ha->value, ha->default_val.str_value);
1758 cc->color_is_mapped = FALSE;
1759 ghid_set_special_colors (ha);
1762 dup_string (&color_file, "");
1763 ghidgui->config_modified = TRUE;
1765 gtk_widget_set_sensitive (config_colors_save_button, FALSE);
1766 gtk_widget_set_sensitive (config_color_warn_label, FALSE);
1767 config_color_file_set_label ();
1768 config_colors_modified = FALSE;
1770 ghid_layer_buttons_color_update ();
1772 /* Receate the colors config page to pick up new colors.
1774 gtk_widget_destroy (config_colors_vbox);
1775 config_colors_tab_create (config_colors_tab_vbox);
1777 ghid_invalidate_all();
1780 static void
1781 config_color_load_cb (gpointer data)
1783 gchar *path, *dir = g_strdup (color_dir);
1785 path = ghid_dialog_file_select_open (_("Load Color File"), &dir, NULL);
1786 if (path)
1788 config_colors_read (path);
1789 dup_string (&color_file, path);
1790 ghidgui->config_modified = TRUE;
1792 gtk_widget_set_sensitive (config_colors_save_button, FALSE);
1793 gtk_widget_set_sensitive (config_color_warn_label, FALSE);
1794 config_color_file_set_label ();
1795 config_colors_modified = FALSE;
1797 g_free (path);
1798 g_free (dir);
1800 /* Receate the colors config page to pick up new colors.
1802 gtk_widget_destroy (config_colors_vbox);
1803 config_colors_tab_create (config_colors_tab_vbox);
1805 ghid_layer_buttons_color_update ();
1806 ghid_invalidate_all();
1809 static void
1810 config_color_save_cb (gpointer data)
1812 gchar *name, *path, *dir = g_strdup (color_dir);
1814 path =
1815 ghid_dialog_file_select_save (_("Save Color File"), &dir, NULL, NULL);
1816 if (path)
1818 name = g_path_get_basename (path);
1819 if (!strcmp (name, "default"))
1820 ghid_dialog_message (_
1821 ("Sorry, not overwriting the default color file!"));
1822 else
1824 config_colors_write (path);
1825 dup_string (&color_file, path);
1826 ghidgui->config_modified = TRUE;
1828 gtk_widget_set_sensitive (config_colors_save_button, FALSE);
1829 gtk_widget_set_sensitive (config_color_warn_label, FALSE);
1830 config_color_file_set_label ();
1831 config_colors_modified = FALSE;
1833 g_free (name);
1835 g_free (path);
1836 g_free (dir);
1839 static void
1840 config_color_set_cb (GtkWidget * button, ConfigColor * cc)
1842 GdkColor new_color;
1843 HID_Attribute *ha = cc->attributes;
1844 gchar *str;
1846 gtk_color_button_get_color (GTK_COLOR_BUTTON (button), &new_color);
1847 str = ghid_get_color_name (&new_color);
1848 ghid_map_color_string (str, &cc->color);
1849 *(char **) ha->value = str;
1850 /* g_free(str); Memory leak */
1852 config_colors_modified = TRUE;
1853 gtk_widget_set_sensitive (config_colors_save_button, TRUE);
1854 gtk_widget_set_sensitive (config_color_warn_label, TRUE);
1856 ghid_set_special_colors (ha);
1857 ghid_layer_buttons_color_update ();
1858 ghid_invalidate_all();
1861 static void
1862 config_color_button_create (GtkWidget * box, ConfigColor * cc)
1864 GtkWidget *button, *hbox, *label;
1865 HID_Attribute *ha = cc->attributes;
1866 gchar *title;
1868 hbox = gtk_hbox_new (FALSE, 6);
1869 gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 0);
1871 if (!cc->color_is_mapped)
1872 ghid_map_color_string (*(char **) ha->value, &cc->color);
1873 cc->color_is_mapped = TRUE;
1875 title = g_strdup_printf (_("PCB %s Color"), ha->name);
1876 button = gtk_color_button_new_with_color (&cc->color);
1877 gtk_color_button_set_title (GTK_COLOR_BUTTON (button), title);
1878 g_free (title);
1880 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1881 label = gtk_label_new (ha->name);
1882 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1883 g_signal_connect (G_OBJECT (button), "color-set",
1884 G_CALLBACK (config_color_set_cb), cc);
1887 static void
1888 config_colors_tab_create (GtkWidget * tab_vbox)
1890 GtkWidget *scrolled_vbox, *vbox, *hbox, *expander, *sep;
1891 GList *list;
1892 ConfigColor *cc;
1894 vbox = gtk_vbox_new (FALSE, 0);
1895 gtk_box_pack_start (GTK_BOX (tab_vbox), vbox, TRUE, TRUE, 0);
1896 gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
1898 config_colors_vbox = vbox; /* can be destroyed if color file loaded */
1899 config_colors_tab_vbox = tab_vbox;
1901 scrolled_vbox = ghid_scrolled_vbox (config_colors_vbox, NULL,
1902 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1904 /* ---- Main colors ---- */
1905 expander = gtk_expander_new (_("Main colors"));
1906 gtk_box_pack_start (GTK_BOX (scrolled_vbox), expander, FALSE, FALSE, 2);
1907 vbox = gtk_vbox_new (FALSE, 0);
1908 gtk_container_add (GTK_CONTAINER (expander), vbox);
1909 vbox = ghid_category_vbox (vbox, NULL, 0, 2, TRUE, FALSE);
1911 for (list = config_color_list; list; list = list->next)
1913 cc = (ConfigColor *) list->data;
1914 if (cc->type != MISC_COLOR)
1915 continue;
1916 config_color_button_create (vbox, cc);
1919 /* ---- Layer colors ---- */
1920 expander = gtk_expander_new (_("Layer colors"));
1921 gtk_box_pack_start (GTK_BOX (scrolled_vbox), expander, FALSE, FALSE, 2);
1922 vbox = gtk_vbox_new (FALSE, 0);
1923 gtk_container_add (GTK_CONTAINER (expander), vbox);
1924 vbox = ghid_category_vbox (vbox, NULL, 0, 2, TRUE, FALSE);
1926 for (list = config_color_list; list; list = list->next)
1928 cc = (ConfigColor *) list->data;
1929 if (cc->type != LAYER_COLOR)
1930 continue;
1931 config_color_button_create (vbox, cc);
1934 /* ---- Selected colors ---- */
1935 expander = gtk_expander_new (_("Selected colors"));
1936 gtk_box_pack_start (GTK_BOX (scrolled_vbox), expander, FALSE, FALSE, 2);
1937 vbox = gtk_vbox_new (FALSE, 0);
1938 gtk_container_add (GTK_CONTAINER (expander), vbox);
1939 vbox = ghid_category_vbox (vbox, NULL, 0, 2, TRUE, FALSE);
1941 for (list = config_color_list; list; list = list->next)
1943 cc = (ConfigColor *) list->data;
1944 if (cc->type != MISC_SELECTED_COLOR)
1945 continue;
1946 config_color_button_create (vbox, cc);
1948 sep = gtk_hseparator_new ();
1949 gtk_box_pack_start (GTK_BOX (vbox), sep, FALSE, FALSE, 2);
1950 for (list = config_color_list; list; list = list->next)
1952 cc = (ConfigColor *) list->data;
1953 if (cc->type != LAYER_SELECTED_COLOR)
1954 continue;
1955 config_color_button_create (vbox, cc);
1958 config_color_warn_label = gtk_label_new ("");
1959 gtk_label_set_use_markup (GTK_LABEL (config_color_warn_label), TRUE);
1960 gtk_label_set_markup (GTK_LABEL (config_color_warn_label),
1961 _("<b>Warning:</b> unsaved color changes will be lost"
1962 " at program exit."));
1963 gtk_box_pack_start (GTK_BOX (config_colors_vbox), config_color_warn_label,
1964 FALSE, FALSE, 4);
1966 hbox = gtk_hbox_new (FALSE, 0);
1967 gtk_box_pack_start (GTK_BOX (config_colors_vbox), hbox, FALSE, FALSE, 6);
1969 config_color_file_label = gtk_label_new ("");
1970 gtk_label_set_use_markup (GTK_LABEL (config_color_file_label), TRUE);
1971 config_color_file_set_label ();
1972 gtk_box_pack_start (GTK_BOX (hbox), config_color_file_label,
1973 FALSE, FALSE, 0);
1975 ghid_button_connected (hbox, NULL, FALSE, FALSE, FALSE, 4,
1976 config_color_load_cb, NULL, _("Load"));
1977 ghid_button_connected (hbox, &config_colors_save_button,
1978 FALSE, FALSE, FALSE, 4,
1979 config_color_save_cb, NULL, _("Save"));
1980 ghid_button_connected (hbox, NULL, FALSE, FALSE, FALSE, 4,
1981 config_color_defaults_cb, NULL, _("Defaults"));
1983 gtk_widget_set_sensitive (config_colors_save_button,
1984 config_colors_modified);
1985 gtk_widget_set_sensitive (config_color_warn_label, config_colors_modified);
1986 gtk_widget_show_all (config_colors_vbox);
1990 /* --------------- The main config page -----------------
1992 enum
1994 CONFIG_NAME_COLUMN,
1995 CONFIG_PAGE_COLUMN,
1996 N_CONFIG_COLUMNS
1999 static GtkNotebook *config_notebook;
2001 static GtkWidget *
2002 config_page_create (GtkTreeStore * tree, GtkTreeIter * iter,
2003 GtkNotebook * notebook)
2005 GtkWidget *vbox;
2006 gint page;
2008 vbox = gtk_vbox_new (FALSE, 0);
2009 gtk_notebook_append_page (notebook, vbox, NULL);
2010 page = gtk_notebook_get_n_pages (notebook) - 1;
2011 gtk_tree_store_set (tree, iter, CONFIG_PAGE_COLUMN, page, -1);
2012 return vbox;
2015 void
2016 ghid_config_handle_units_changed (void)
2018 gchar *text = pcb_g_strdup_printf ("<b>%s</b>",
2019 Settings.grid_unit->in_suffix);
2020 ghid_set_cursor_position_labels ();
2021 gtk_label_set_markup (GTK_LABEL (ghidgui->grid_units_label), text);
2022 g_free (text);
2024 if (config_sizes_vbox)
2026 gtk_widget_destroy (config_sizes_vbox);
2027 config_sizes_vbox = NULL;
2028 config_sizes_tab_create (config_sizes_tab_vbox);
2030 if (config_increments_vbox)
2032 gtk_widget_destroy (config_increments_vbox);
2033 config_increments_vbox = NULL;
2034 config_increments_tab_create (config_increments_tab_vbox);
2036 ghidgui->config_modified = TRUE;
2039 void
2040 ghid_config_text_scale_update (void)
2042 if (config_window)
2043 gtk_spin_button_set_value (GTK_SPIN_BUTTON (config_text_spin_button),
2044 (gdouble) Settings.TextScale);
2047 static void
2048 config_close_cb (gpointer data)
2050 /* Config pages may need to check for modified entries, use as default
2051 | options, etc when the config window is closed.
2053 config_sizes_apply ();
2054 config_layers_apply ();
2055 config_library_apply ();
2056 config_general_apply ();
2058 config_sizes_vbox = NULL;
2059 config_increments_vbox = NULL;
2061 config_groups_vbox = config_groups_table = NULL;
2062 config_groups_window = NULL;
2064 gtk_widget_destroy (config_window);
2065 config_window = NULL;
2068 static void
2069 config_destroy_cb (gpointer data)
2071 config_sizes_vbox = NULL;
2072 config_increments_vbox = NULL;
2073 config_groups_vbox = config_groups_table = NULL;
2074 config_groups_window = NULL;
2075 gtk_widget_destroy (config_window);
2076 config_window = NULL;
2079 static void
2080 config_selection_changed_cb (GtkTreeSelection * selection, gpointer data)
2082 GtkTreeIter iter;
2083 GtkTreeModel *model;
2084 gint page;
2086 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
2087 return;
2088 gtk_tree_model_get (model, &iter, CONFIG_PAGE_COLUMN, &page, -1);
2089 gtk_notebook_set_current_page (config_notebook, page);
2092 void
2093 ghid_config_window_show (void)
2095 GtkWidget *widget, *main_vbox, *vbox, *config_hbox, *hbox;
2096 GtkWidget *scrolled;
2097 GtkWidget *button;
2098 GtkTreeStore *model;
2099 GtkTreeView *treeview;
2100 GtkTreeIter iter;
2101 GtkCellRenderer *renderer;
2102 GtkTreeViewColumn *column;
2103 GtkTreeSelection *select;
2105 if (config_window)
2107 gtk_window_present (GTK_WINDOW (config_window));
2108 return;
2111 config_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2112 g_signal_connect (G_OBJECT (config_window), "delete_event",
2113 G_CALLBACK (config_destroy_cb), NULL);
2115 gtk_window_set_title (GTK_WINDOW (config_window), _("PCB Preferences"));
2116 gtk_window_set_wmclass (GTK_WINDOW (config_window), "Pcb_Conf", "PCB");
2117 gtk_container_set_border_width (GTK_CONTAINER (config_window), 2);
2119 config_hbox = gtk_hbox_new (FALSE, 4);
2120 gtk_container_add (GTK_CONTAINER (config_window), config_hbox);
2122 scrolled = gtk_scrolled_window_new (NULL, NULL);
2123 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
2124 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
2125 gtk_box_pack_start (GTK_BOX (config_hbox), scrolled, FALSE, FALSE, 0);
2127 main_vbox = gtk_vbox_new (FALSE, 4);
2128 gtk_box_pack_start (GTK_BOX (config_hbox), main_vbox, TRUE, TRUE, 0);
2130 widget = gtk_notebook_new ();
2131 gtk_box_pack_start (GTK_BOX (main_vbox), widget, TRUE, TRUE, 0);
2132 config_notebook = GTK_NOTEBOOK (widget);
2133 gtk_notebook_set_show_tabs (config_notebook, FALSE);
2135 model = gtk_tree_store_new (N_CONFIG_COLUMNS, G_TYPE_STRING, G_TYPE_INT);
2138 /* -- General -- */
2139 gtk_tree_store_append (model, &iter, NULL);
2140 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("General"), -1);
2141 vbox = config_page_create (model, &iter, config_notebook);
2142 config_general_tab_create (vbox);
2145 /* -- Sizes -- */
2146 gtk_tree_store_append (model, &iter, NULL);
2147 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("Sizes"), -1);
2148 vbox = config_page_create (model, &iter, config_notebook);
2149 config_sizes_tab_create (vbox);
2151 /* -- Increments -- */
2152 gtk_tree_store_append (model, &iter, NULL);
2153 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("Increments"), -1);
2154 vbox = config_page_create (model, &iter, config_notebook);
2155 config_increments_tab_create (vbox);
2157 /* -- Library -- */
2158 gtk_tree_store_append (model, &iter, NULL);
2159 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("Library"), -1);
2160 vbox = config_page_create (model, &iter, config_notebook);
2161 config_library_tab_create (vbox);
2163 /* -- Layer names and groups -- */
2164 gtk_tree_store_append (model, &iter, NULL);
2165 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("Layers"), -1);
2166 vbox = config_page_create (model, &iter, config_notebook);
2167 config_layers_tab_create (vbox);
2170 /* -- Colors -- */
2171 gtk_tree_store_append (model, &iter, NULL);
2172 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("Colors"), -1);
2173 vbox = config_page_create (model, &iter, config_notebook);
2174 config_colors_tab_create (vbox);
2177 /* Create the tree view
2179 treeview =
2180 GTK_TREE_VIEW (gtk_tree_view_new_with_model (GTK_TREE_MODEL (model)));
2181 g_object_unref (G_OBJECT (model)); /* Don't need the model anymore */
2183 renderer = gtk_cell_renderer_text_new ();
2184 column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
2185 "text",
2186 CONFIG_NAME_COLUMN,
2187 NULL);
2188 gtk_tree_view_append_column (treeview, column);
2189 gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (treeview));
2192 select = gtk_tree_view_get_selection (treeview);
2193 gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
2194 g_signal_connect (G_OBJECT (select), "changed",
2195 G_CALLBACK (config_selection_changed_cb), NULL);
2198 hbox = gtk_hbutton_box_new ();
2199 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
2200 gtk_box_set_spacing (GTK_BOX (hbox), 5);
2201 gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
2203 button = gtk_button_new_from_stock (GTK_STOCK_OK);
2204 gtk_widget_set_can_default (button, TRUE);
2205 g_signal_connect (G_OBJECT (button), "clicked",
2206 G_CALLBACK (config_close_cb), NULL);
2207 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
2208 gtk_widget_grab_default (button);
2210 gtk_widget_show_all (config_window);