Add grid-increment-mm (and similar) settings
[geda-pcb/whiteaudio.git] / src / hid / gtk / gui-config.c
blobafb2235151b102eb201788c65936b6068b606106
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);
59 enum ConfigType
61 CONFIG_Boolean,
62 CONFIG_Integer,
63 CONFIG_Coord,
64 CONFIG_Real,
65 CONFIG_String,
66 CONFIG_Unused
69 typedef struct
71 gchar *name;
72 enum ConfigType type;
73 void *value;
75 ConfigAttribute;
78 enum ColorTypes
80 MISC_COLOR,
81 MISC_SELECTED_COLOR,
82 LAYER_COLOR,
83 LAYER_SELECTED_COLOR
86 typedef struct
88 HID_Attribute *attributes;
89 enum ColorTypes type;
90 GdkColor color;
91 gboolean color_is_mapped;
93 ConfigColor;
95 static GList *config_color_list, *lib_newlib_list;
97 static gchar *lib_newlib_config, *board_size_override;
100 static gchar *color_file;
102 extern void ghid_set_special_colors (HID_Attribute * ha);
105 #define PCB_CONFIG_DIR ".pcb"
106 #define PCB_CONFIG_FILE "preferences"
107 #define PCB_COLORS_DIR "colors"
109 static gchar *config_dir, *color_dir;
111 /* CONFIG_Unused types are expected to be found in main_attribute_list and
112 | will be assigned the type found there. NULL value pointers here are
113 | also expected to be assigned values from the main_attribute_list.
115 /* PinoutFont also not used anymore */
117 static ConfigAttribute config_attributes[] = {
118 {"gui-compact-horizontal", CONFIG_Boolean, &_ghidgui.compact_horizontal},
119 {"gui-compact-vertical", CONFIG_Boolean, &_ghidgui.compact_vertical},
120 {"use-command-window", CONFIG_Boolean, &_ghidgui.use_command_window},
121 {"save-in-tmp", CONFIG_Unused, NULL},
122 {"grid-units", CONFIG_Unused, NULL},
123 {"grid", CONFIG_Unused, NULL},
125 {"grid-increment-mm", CONFIG_Unused, NULL},
126 {"line-increment-mm", CONFIG_Unused, NULL},
127 {"size-increment-mm", CONFIG_Unused, NULL},
128 {"clear-increment-mm", CONFIG_Unused, NULL},
129 {"grid-increment-mil", CONFIG_Unused, NULL},
130 {"line-increment-mil", CONFIG_Unused, NULL},
131 {"size-increment-mil", CONFIG_Unused, NULL},
132 {"clear-increment-mil", CONFIG_Unused, NULL},
134 {"history-size", CONFIG_Integer, &_ghidgui.history_size},
135 {"top-window-width", CONFIG_Integer, &_ghidgui.top_window_width},
136 {"top-window-height", CONFIG_Integer, &_ghidgui.top_window_height},
137 {"log-window-width", CONFIG_Integer, &_ghidgui.log_window_width},
138 {"log-window-height", CONFIG_Integer, &_ghidgui.log_window_height},
139 {"drc-window-width", CONFIG_Integer, &_ghidgui.drc_window_width},
140 {"drc-window-height", CONFIG_Integer, &_ghidgui.drc_window_height},
141 {"library-window-width", CONFIG_Integer, &_ghidgui.library_window_width},
142 {"library-window-height", CONFIG_Integer, &_ghidgui.library_window_height},
143 {"netlist-window-height", CONFIG_Integer, &_ghidgui.netlist_window_height},
144 {"keyref-window-width", CONFIG_Integer, &_ghidgui.keyref_window_width},
145 {"keyref-window-height", CONFIG_Integer, &_ghidgui.keyref_window_height},
146 {"text-scale", CONFIG_Unused, NULL},
147 {"via-thickness", CONFIG_Unused, NULL},
148 {"via-drilling-hole", CONFIG_Unused, NULL},
149 {"backup-interval", CONFIG_Unused, NULL},
150 {"line-thickness", CONFIG_Unused, NULL},
151 {"rat-thickness", CONFIG_Unused, NULL},
152 {"bloat", CONFIG_Unused, NULL},
153 {"shrink", CONFIG_Unused, NULL},
154 {"min-width", CONFIG_Unused, NULL},
155 {"min-silk", CONFIG_Unused, NULL},
156 {"min-drill", CONFIG_Unused, NULL},
157 {"min-ring", CONFIG_Unused, NULL},
158 {"default-PCB-width", CONFIG_Unused, NULL},
159 {"default-PCB-height", CONFIG_Unused, NULL},
161 {"groups", CONFIG_Unused, NULL},
162 {"route-styles", CONFIG_Unused, NULL},
163 {"library-newlib", CONFIG_String, &lib_newlib_config},
164 {"color-file", CONFIG_String, &color_file},
165 /* FIXME: construct layer-names- in a list */
166 {"layer-name-1", CONFIG_Unused, NULL},
167 {"layer-name-2", CONFIG_Unused, NULL},
168 {"layer-name-3", CONFIG_Unused, NULL},
169 {"layer-name-4", CONFIG_Unused, NULL},
170 {"layer-name-5", CONFIG_Unused, NULL},
171 {"layer-name-6", CONFIG_Unused, NULL},
172 {"layer-name-7", CONFIG_Unused, NULL},
173 {"layer-name-8", CONFIG_Unused, NULL},
176 static gboolean
177 dup_core_string (gchar ** dst, const gchar * src)
179 if (dst == NULL || (*dst == NULL && src == NULL))
180 return FALSE;
182 if (*dst != NULL && src != NULL && strcmp (*dst, src) == 0)
183 return FALSE;
185 free (*dst);
186 *dst = (src == NULL) ? NULL : strdup (src);
188 return TRUE;
191 static FILE *
192 config_file_open (gchar * mode)
194 FILE *f;
195 gchar *homedir, *fname;
198 homedir = (gchar *) g_get_home_dir ();
199 if (!homedir)
201 g_message ("config_file_open: Can't get home directory!");
202 return NULL;
205 if (!config_dir)
207 config_dir =
208 g_build_path (G_DIR_SEPARATOR_S, homedir, PCB_CONFIG_DIR, NULL);
209 if (!g_file_test (config_dir, G_FILE_TEST_IS_DIR)
210 && MKDIR (config_dir, 0755) < 0)
212 g_message ("config_file_open: Can't make \"%s\" directory!",
213 config_dir);
214 g_free (config_dir);
215 config_dir = NULL;
216 return NULL;
220 if (!color_dir) /* Convenient to make the color dir here */
222 color_dir =
223 g_build_path (G_DIR_SEPARATOR_S, config_dir, PCB_COLORS_DIR, NULL);
224 if (!g_file_test (color_dir, G_FILE_TEST_IS_DIR))
226 if (MKDIR (color_dir, 0755) < 0)
228 g_message ("config_file_open: Can't make \"%s\" directory!",
229 color_dir);
230 g_free (color_dir);
231 color_dir = NULL;
233 fname = g_build_path (G_DIR_SEPARATOR_S,
234 color_dir, "Default", NULL);
235 dup_string (&color_file, fname);
236 g_free (fname);
240 fname = g_build_path (G_DIR_SEPARATOR_S, config_dir, PCB_CONFIG_FILE, NULL);
241 f = fopen (fname, mode);
243 g_free (fname);
244 return f;
247 static ConfigAttribute *
248 lookup_config_attribute (gchar * name, gboolean if_null_value)
250 ConfigAttribute *ca;
252 for (ca = &config_attributes[0];
253 ca < &config_attributes[0] + G_N_ELEMENTS (config_attributes); ++ca)
255 if (name && (!strcmp (name, ca->name)))
257 if (ca->value && if_null_value)
258 break;
259 return ca;
262 return NULL;
265 void
266 ghid_config_init (void)
268 HID_AttrNode *ha;
269 HID_Attribute *a;
270 ConfigAttribute *ca, dummy_attribute;
271 ConfigColor *cc;
272 gint len;
274 ghidgui->n_mode_button_columns = 3;
275 ghidgui->small_label_markup = TRUE;
276 ghidgui->history_size = 5;
277 dup_string (&color_file, "");
279 for (ha = hid_attr_nodes; ha; ha = ha->next)
281 for (a = ha->attributes; a < ha->attributes + ha->n; ++a)
283 if (!a->value)
284 continue;
285 if ((ca = lookup_config_attribute (a->name, TRUE)) == NULL)
286 ca = &dummy_attribute;
287 ca->value = a->value; /* Typically &Setting.xxx */
288 ca->type = CONFIG_Unused;
289 switch (a->type)
291 case HID_Boolean:
292 *(char *) a->value = a->default_val.int_value;
293 ca->type = CONFIG_Boolean;
294 break;
295 case HID_Integer:
296 *(int *) a->value = a->default_val.int_value;
297 ca->type = CONFIG_Integer;
298 break;
299 case HID_Coord:
300 *(Coord *) a->value = a->default_val.coord_value;
301 ca->type = CONFIG_Coord;
302 break;
303 case HID_Real:
304 *(double *) a->value = a->default_val.real_value;
305 ca->type = CONFIG_Real;
306 break;
308 case HID_String:
309 if (!a->name)
310 break;
311 *(char **) a->value = g_strdup (a->default_val.str_value);
312 ca->type = CONFIG_String;
314 len = strlen (a->name);
315 if (len < 7 || strstr (a->name, "color") == NULL)
316 break;
318 cc = g_new0 (ConfigColor, 1);
319 cc->attributes = a;
321 if (!strncmp (a->name, "layer-color", 11))
322 cc->type = LAYER_COLOR;
323 else if (!strncmp (a->name, "layer-selected-color", 20))
324 cc->type = LAYER_SELECTED_COLOR;
325 else if (!strncmp (a->name + len - 14, "selected-color", 14))
326 cc->type = MISC_SELECTED_COLOR;
327 else
328 cc->type = MISC_COLOR;
330 config_color_list = g_list_append (config_color_list, cc);
331 break;
333 case HID_Enum:
334 case HID_Unit:
335 *(int *) a->value = a->default_val.int_value;
336 break;
338 case HID_Label:
339 case HID_Mixed:
340 case HID_Path:
341 break;
342 default:
343 abort ();
349 static gint
350 parse_option_line (gchar * line, gchar ** option_result, gchar ** arg_result)
352 gchar *s, *ss, option[64], arg[512];
353 gint argc = 1;
355 if (option_result)
356 *option_result = NULL;
357 if (arg_result)
358 *arg_result = NULL;
360 s = line;
361 while (*s == ' ' || *s == '\t')
362 ++s;
363 if (!*s || *s == '\n' || *s == '#' || *s == '[')
364 return 0;
365 if ((ss = strchr (s, '\n')) != NULL)
366 *ss = '\0';
367 arg[0] = '\0';
368 sscanf (s, "%63s %511[^\n]", option, arg);
370 s = option; /* Strip trailing ':' or '=' */
371 while (*s && *s != ':' && *s != '=')
372 ++s;
373 *s = '\0';
375 s = arg; /* Strip leading ':', '=', and whitespace */
376 while (*s == ' ' || *s == '\t' || *s == ':' || *s == '=' || *s == '"')
377 ++s;
378 if ((ss = strchr (s, '"')) != NULL)
379 *ss = '\0';
381 if (option_result)
382 *option_result = g_strdup (option);
383 if (arg_result && *s)
385 *arg_result = g_strdup (s);
386 ++argc;
388 return argc;
391 static gboolean
392 set_config_attribute (gchar * option, gchar * arg)
394 ConfigAttribute *ca;
395 #if 0
396 struct lconv *lc;
397 gchar locale_point, *comma_point, *period_point;
399 /* Until LC_NUMERIC is totally resolved, check if we need to decimal
400 | point convert. Ultimately, data files will be POSIX and gui
401 | presentation (hence the config file reals) will be in the users locale.
403 lc = localeconv ();
404 locale_point = *lc->decimal_point;
405 #endif
407 if ((ca = lookup_config_attribute (option, FALSE)) == NULL)
408 return FALSE;
409 switch (ca->type)
411 case CONFIG_Boolean:
412 *(gchar *) ca->value = (gchar) atoi (arg);
413 break;
415 case CONFIG_Integer:
416 *(gint *) ca->value = atoi (arg);
417 break;
419 case CONFIG_Real:
420 /* Hopefully temporary locale decimal point check:
422 #if 0
423 comma_point = strrchr (arg, ',');
424 period_point = strrchr (arg, '.');
425 if (comma_point && *comma_point != locale_point)
426 *comma_point = locale_point;
427 else if (period_point && *period_point != locale_point)
428 *period_point = locale_point;
429 #endif
430 *(double *) ca->value = atof (arg);
431 break;
433 case CONFIG_String:
434 dup_string ((gchar **) ca->value, arg ? arg : (gchar *)"");
435 break;
436 case CONFIG_Coord:
437 *(Coord *) ca->value = GetValue (arg, NULL, NULL);
438 break;
439 default:
440 break;
442 return TRUE;
445 static void
446 config_file_read (void)
448 FILE *f;
449 gchar buf[512], *option, *arg;
451 if ((f = config_file_open ("r")) == NULL)
452 return;
454 buf[0] = '\0';
455 while (fgets (buf, sizeof (buf), f))
457 if (parse_option_line (buf, &option, &arg) > 0)
458 set_config_attribute (option, arg);
459 g_free (option);
460 g_free (arg);
463 fclose (f);
466 static void
467 config_colors_write (gchar * path)
469 FILE *f;
470 GList *list;
471 HID_Attribute *ha;
472 ConfigColor *cc;
474 if ((f = fopen (path, "w")) == NULL)
475 return;
476 for (list = config_color_list; list; list = list->next)
478 cc = (ConfigColor *) list->data;
479 ha = cc->attributes;
480 fprintf (f, "%s =\t%s\n", ha->name, *(char **) ha->value);
482 fclose (f);
485 static gboolean
486 config_colors_read (gchar * path)
488 FILE *f;
489 GList *list;
490 ConfigColor *cc;
491 HID_Attribute *ha;
492 gchar *s, buf[512], option[64], arg[512];
494 if (!path || !*path || (f = fopen (path, "r")) == NULL)
495 return FALSE;
497 while (fgets (buf, sizeof (buf), f))
499 sscanf (buf, "%63s %511[^\n]", option, arg);
500 s = option; /* Strip trailing ':' or '=' */
501 while (*s && *s != ':' && *s != '=')
502 ++s;
503 *s = '\0';
504 s = arg; /* Strip leading ':', '=', and whitespace */
505 while (*s == ' ' || *s == '\t' || *s == ':' || *s == '=')
506 ++s;
508 for (list = config_color_list; list; list = list->next)
510 cc = (ConfigColor *) list->data;
511 ha = cc->attributes;
512 if (!strcmp (option, ha->name))
514 *(char **) ha->value = g_strdup (s);
515 cc->color_is_mapped = FALSE;
516 ghid_set_special_colors (ha);
517 break;
521 fclose (f);
523 return TRUE;
526 static gchar *
527 expand_dir (gchar * dir)
529 gchar *s;
531 if (*dir == '~')
532 s = g_build_filename ((gchar *) g_get_home_dir (), dir + 1, NULL);
533 else
534 s = g_strdup (dir);
535 return s;
538 static void
539 add_to_paths_list (GList ** list, gchar * path_string)
541 gchar *p, *paths;
543 paths = g_strdup (path_string);
544 for (p = strtok (paths, PCB_PATH_DELIMETER); p && *p; p = strtok (NULL, PCB_PATH_DELIMETER))
545 *list = g_list_prepend (*list, expand_dir (p));
546 g_free (paths);
549 /* Parse command line code borrowed from hid/common/hidinit.c
551 static void
552 parse_optionv (gint * argc, gchar *** argv, gboolean from_cmd_line)
554 HID_AttrNode *ha;
555 HID_Attribute *a;
556 const Unit *unit;
557 gchar *ep;
558 gint e, ok, offset;
559 gboolean matched = FALSE;
561 offset = from_cmd_line ? 2 : 0;
563 while (*argc
564 && (((*argv)[0][0] == '-' && (*argv)[0][1] == '-')
565 || !from_cmd_line))
567 for (ha = hid_attr_nodes; ha; ha = ha->next)
569 for (a = ha->attributes; a < ha->attributes + ha->n; ++a)
571 if (!a->name || strcmp ((*argv)[0] + offset, a->name))
572 continue;
573 switch (a->type)
575 case HID_Label:
576 break;
577 case HID_Integer:
578 if (a->value)
579 *(int *) a->value = strtol ((*argv)[1], 0, 0);
580 else
581 a->default_val.int_value = strtol ((*argv)[1], 0, 0);
582 (*argc)--;
583 (*argv)++;
584 break;
585 case HID_Coord:
586 if (a->value)
587 *(Coord *) a->value = GetValue ((*argv)[1], 0, 0);
588 else
589 a->default_val.coord_value = GetValue ((*argv)[1], 0, 0);
590 (*argc)--;
591 (*argv)++;
592 break;
593 case HID_Real:
594 if (a->value)
595 *(double *) a->value = strtod ((*argv)[1], 0);
596 else
597 a->default_val.real_value = strtod ((*argv)[1], 0);
598 (*argc)--;
599 (*argv)++;
600 break;
601 case HID_String:
602 if (a->value)
603 *(char **) a->value = g_strdup((*argv)[1]);
604 else
605 a->default_val.str_value = g_strdup((*argv)[1]);
606 (*argc)--;
607 (*argv)++;
608 break;
609 case HID_Boolean:
610 if (a->value)
611 *(char *) a->value = 1;
612 else
613 a->default_val.int_value = 1;
614 break;
615 case HID_Mixed:
616 a->default_val.real_value = strtod ((*argv)[1], &ep);
617 goto do_enum;
618 case HID_Enum:
619 ep = (*argv)[1];
620 do_enum:
621 ok = 0;
622 for (e = 0; a->enumerations[e]; e++)
623 if (strcmp (a->enumerations[e], ep) == 0)
625 ok = 1;
626 a->default_val.int_value = e;
627 a->default_val.str_value = ep;
628 break;
630 if (!ok)
632 fprintf (stderr,
633 "ERROR: \"%s\" is an unknown value for the --%s option\n",
634 (*argv)[1], a->name);
635 exit (1);
637 (*argc)--;
638 (*argv)++;
639 break;
640 case HID_Path:
641 abort ();
642 a->default_val.str_value = (*argv)[1];
643 (*argc)--;
644 (*argv)++;
645 break;
646 case HID_Unit:
647 unit = get_unit_struct ((*argv)[1]);
648 if (unit == NULL)
650 fprintf (stderr,
651 "ERROR: unit \"%s\" is unknown to pcb (option --%s)\n",
652 (*argv)[1], a->name);
653 exit (1);
655 a->default_val.int_value = unit->index;
656 a->default_val.str_value = unit->suffix;
657 (*argc)--;
658 (*argv)++;
659 break;
661 (*argc)--;
662 (*argv)++;
663 ha = 0;
664 goto got_match;
666 if (a < ha->attributes + ha->n)
667 matched = TRUE;
669 if (!matched)
671 if (from_cmd_line)
673 fprintf (stderr, "unrecognized option: %s\n", (*argv)[0]);
674 exit (1);
676 else
677 // ghid_log("unrecognized option: %s\n", (*argv)[0]);
678 fprintf (stderr, "unrecognized option: %s\n", (*argv)[0]);
680 got_match:;
682 (*argc)++;
683 (*argv)--;
686 static void
687 load_rc_file (gchar * path)
689 FILE *f;
690 gchar buf[1024], *av[2], **argv;
691 gint argc;
693 f = fopen (path, "r");
694 if (!f)
695 return;
697 if (Settings.verbose)
698 printf ("Loading pcbrc file: %s\n", path);
699 while (fgets (buf, sizeof (buf), f))
701 argv = &(av[0]);
702 if ((argc = parse_option_line (buf, &av[0], &av[1])) > 0)
703 parse_optionv (&argc, &argv, FALSE);
704 g_free (av[0]);
705 g_free (av[1]);
707 fclose (f);
710 static void
711 load_rc_files (void)
713 gchar *path;
715 load_rc_file ("/etc/pcbrc");
716 load_rc_file ("/usr/local/etc/pcbrc");
718 path = g_build_filename (pcblibdir, "pcbrc", NULL);
719 load_rc_file (path);
720 g_free (path);
722 path = g_build_filename ((gchar *) g_get_home_dir (), ".pcb/pcbrc", NULL);
723 load_rc_file (path);
724 g_free (path);
726 load_rc_file ("pcbrc");
730 void
731 ghid_config_files_read (gint * argc, gchar *** argv)
733 GList *list;
734 gchar *str, *dir;
735 gint width, height;
737 ghidgui = &_ghidgui;
739 ghid_config_init ();
740 load_rc_files ();
741 config_file_read ();
742 config_colors_read (color_file);
743 (*argc)--;
744 (*argv)++;
745 parse_optionv (argc, argv, TRUE);
747 if (board_size_override
748 && sscanf (board_size_override, "%dx%d", &width, &height) == 2)
750 Settings.MaxWidth = TO_PCB_UNITS (width);
751 Settings.MaxHeight = TO_PCB_UNITS (height);
754 if (lib_newlib_config && *lib_newlib_config)
755 add_to_paths_list (&lib_newlib_list, lib_newlib_config);
757 for (list = lib_newlib_list; list; list = list->next)
759 str = Settings.LibraryTree;
760 dir = expand_dir ((gchar *) list->data);
761 Settings.LibraryTree = g_strconcat (str, PCB_PATH_DELIMETER, dir, NULL);
762 g_free (dir);
763 g_free (str);
767 void
768 ghid_config_files_write (void)
770 FILE *f;
771 ConfigAttribute *ca;
773 if (!ghidgui->config_modified || (f = config_file_open ("w")) == NULL)
774 return;
776 fprintf (f, "### PCB configuration file. ###\n");
778 for (ca = &config_attributes[0];
779 ca < &config_attributes[0] + G_N_ELEMENTS (config_attributes); ++ca)
781 switch (ca->type)
783 case CONFIG_Boolean:
784 fprintf (f, "%s = %d\n", ca->name, (gint) * (gchar *) ca->value);
785 break;
787 case CONFIG_Integer:
788 fprintf (f, "%s = %d\n", ca->name, *(gint *) ca->value);
789 break;
791 case CONFIG_Real:
792 fprintf (f, "%s = %f\n", ca->name, *(double *) ca->value);
793 break;
795 case CONFIG_String:
796 if (*(char **) ca->value == NULL)
797 fprintf (f, "# %s = NULL\n", ca->name);
798 else
799 fprintf (f, "%s = %s\n", ca->name, *(char **) ca->value);
800 break;
801 default:
802 break;
805 fclose (f);
807 ghidgui->config_modified = FALSE;
810 /* =================== OK, now the gui stuff ======================
812 static GtkWidget *config_window;
814 /* -------------- The General config page ----------------
817 static void
818 config_command_window_toggle_cb (GtkToggleButton * button, gpointer data)
820 gboolean active = gtk_toggle_button_get_active (button);
821 static gboolean holdoff;
823 if (holdoff)
824 return;
826 /* Can't toggle into command window mode if the status line command
827 | entry is active.
829 if (ghidgui->command_entry_status_line_active)
831 holdoff = TRUE;
832 gtk_toggle_button_set_active (button, FALSE);
833 holdoff = FALSE;
834 return;
836 ghidgui->use_command_window = active;
837 ghid_command_use_command_window_sync ();
841 static void
842 config_compact_horizontal_toggle_cb (GtkToggleButton * button, gpointer data)
844 gboolean active = gtk_toggle_button_get_active (button);
846 ghidgui->compact_horizontal = active;
847 ghid_set_status_line_label ();
848 ghidgui->config_modified = TRUE;
851 static void
852 config_compact_vertical_toggle_cb (GtkToggleButton * button, gpointer data)
854 gboolean active = gtk_toggle_button_get_active (button);
856 ghidgui->compact_vertical = active;
857 ghid_pack_mode_buttons();
858 ghidgui->config_modified = TRUE;
861 static void
862 config_general_toggle_cb (GtkToggleButton * button, void * setting)
864 *(gint *)setting = gtk_toggle_button_get_active (button);
865 ghidgui->config_modified = TRUE;
868 static void
869 config_backup_spin_button_cb (GtkSpinButton * spin_button, gpointer data)
871 Settings.BackupInterval = gtk_spin_button_get_value_as_int (spin_button);
872 EnableAutosave ();
873 ghidgui->config_modified = TRUE;
876 static void
877 config_history_spin_button_cb (GtkSpinButton * spin_button, gpointer data)
879 ghidgui->history_size = gtk_spin_button_get_value_as_int (spin_button);
880 ghidgui->config_modified = TRUE;
883 static void
884 config_general_tab_create (GtkWidget * tab_vbox)
886 GtkWidget *vbox;
888 gtk_container_set_border_width (GTK_CONTAINER (tab_vbox), 6);
890 vbox = ghid_category_vbox (tab_vbox, _("Enables"), 4, 2, TRUE, TRUE);
892 ghid_check_button_connected (vbox, NULL, ghidgui->use_command_window,
893 TRUE, FALSE, FALSE, 2,
894 config_command_window_toggle_cb, NULL,
895 _("Use separate window for command entry"));
897 ghid_check_button_connected (vbox, NULL, ghidgui->compact_horizontal,
898 TRUE, FALSE, FALSE, 2,
899 config_compact_horizontal_toggle_cb, NULL,
900 _("Alternate window layout to allow smaller horizontal size"));
902 ghid_check_button_connected (vbox, NULL, ghidgui->compact_vertical,
903 TRUE, FALSE, FALSE, 2,
904 config_compact_vertical_toggle_cb, NULL,
905 _("Alternate window layout to allow smaller vertical size"));
907 vbox = ghid_category_vbox (tab_vbox, _("Backups"), 4, 2, TRUE, TRUE);
908 ghid_check_button_connected (vbox, NULL, Settings.SaveInTMP,
909 TRUE, FALSE, FALSE, 2,
910 config_general_toggle_cb, &Settings.SaveInTMP,
911 _("If layout is modified at exit, save into PCB.%i.save"));
912 ghid_spin_button (vbox, NULL, Settings.BackupInterval, 0.0, 60 * 60, 60.0,
913 600.0, 0, 0, config_backup_spin_button_cb, NULL, FALSE,
914 _("Seconds between auto backups\n"
915 "(set to zero to disable auto backups)"));
917 vbox = ghid_category_vbox (tab_vbox, _("Misc"), 4, 2, TRUE, TRUE);
918 ghid_spin_button (vbox, NULL, ghidgui->history_size,
919 5.0, 25.0, 1.0, 1.0, 0, 0,
920 config_history_spin_button_cb, NULL, FALSE,
921 _("Number of commands to remember in the history list"));
925 static void
926 config_general_apply (void)
928 /* save the settings */
929 ghid_config_files_write ();
933 /* -------------- The Sizes config page ----------------
936 static GtkWidget *config_sizes_vbox,
937 *config_sizes_tab_vbox, *config_text_spin_button;
939 static GtkWidget *use_board_size_default_button,
940 *use_drc_sizes_default_button;
942 static Coord new_board_width, new_board_height;
944 static void
945 config_sizes_apply (void)
947 gboolean active;
949 active =
950 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
951 (use_board_size_default_button));
952 if (active)
954 Settings.MaxWidth = new_board_width;
955 Settings.MaxHeight = new_board_height;
956 ghidgui->config_modified = TRUE;
959 active =
960 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
961 (use_drc_sizes_default_button));
962 if (active)
964 Settings.Bloat = PCB->Bloat;
965 Settings.Shrink = PCB->Shrink;
966 Settings.minWid = PCB->minWid;
967 Settings.minSlk = PCB->minSlk;
968 Settings.IsleArea = PCB->IsleArea;
969 Settings.minDrill = PCB->minDrill;
970 Settings.minRing = PCB->minRing;
971 ghidgui->config_modified = TRUE;
974 if (PCB->MaxWidth != new_board_width || PCB->MaxHeight != new_board_height)
975 ChangePCBSize (new_board_width, new_board_height);
978 static void
979 text_spin_button_cb (GtkSpinButton * spin, void * dst)
981 *(gint *)dst = gtk_spin_button_get_value_as_int (spin);
982 ghidgui->config_modified = TRUE;
983 ghid_set_status_line_label ();
986 static void
987 coord_entry_cb (GHidCoordEntry * ce, void * dst)
989 *(Coord *) dst = ghid_coord_entry_get_value (ce);
990 ghidgui->config_modified = TRUE;
993 static void
994 config_sizes_tab_create (GtkWidget * tab_vbox)
996 GtkWidget *table, *vbox, *hbox;
998 /* Need a vbox we can destroy if user changes grid units.
1000 if (!config_sizes_vbox)
1002 vbox = gtk_vbox_new (FALSE, 0);
1003 gtk_box_pack_start (GTK_BOX (tab_vbox), vbox, FALSE, FALSE, 0);
1004 gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
1005 config_sizes_vbox = vbox;
1006 config_sizes_tab_vbox = tab_vbox;
1009 /* ---- Board Size ---- */
1010 vbox = ghid_category_vbox (config_sizes_vbox, _("Board Size"),
1011 4, 2, TRUE, TRUE);
1012 hbox = gtk_hbox_new (FALSE, 0);
1013 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1014 table = gtk_table_new (2, 2, FALSE);
1015 gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
1016 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1017 gtk_table_set_row_spacings (GTK_TABLE (table), 3);
1019 new_board_width = PCB->MaxWidth;
1020 new_board_height = PCB->MaxHeight;
1021 ghid_table_coord_entry (table, 0, 0, NULL,
1022 PCB->MaxWidth, MIN_SIZE, MAX_COORD,
1023 CE_LARGE, 0, coord_entry_cb,
1024 &new_board_width, FALSE, _("Width"));
1026 ghid_table_coord_entry (table, 1, 0, NULL,
1027 PCB->MaxHeight, MIN_SIZE, MAX_COORD,
1028 CE_LARGE, 0, coord_entry_cb,
1029 &new_board_height, FALSE, _("Height"));
1030 ghid_check_button_connected (vbox, &use_board_size_default_button, FALSE,
1031 TRUE, FALSE, FALSE, 0, NULL, NULL,
1032 _("Use this board size as the default for new layouts"));
1034 /* ---- Text Scale ---- */
1035 vbox = ghid_category_vbox (config_sizes_vbox, _("Text Scale"),
1036 4, 2, TRUE, TRUE);
1037 hbox = gtk_hbox_new (FALSE, 0);
1038 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1039 table = gtk_table_new (4, 2, FALSE);
1040 gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
1041 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1042 gtk_table_set_row_spacings (GTK_TABLE (table), 3);
1044 ghid_table_spin_button (table, 0, 0, &config_text_spin_button,
1045 Settings.TextScale,
1046 MIN_TEXTSCALE, MAX_TEXTSCALE,
1047 10.0, 10.0,
1048 0, 0, text_spin_button_cb,
1049 &Settings.TextScale, FALSE, "%");
1052 /* ---- DRC Sizes ---- */
1053 vbox = ghid_category_vbox (config_sizes_vbox, _("Design Rule Checking"),
1054 4, 2, TRUE, TRUE);
1055 hbox = gtk_hbox_new (FALSE, 0);
1056 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1057 table = gtk_table_new (4, 2, FALSE);
1058 gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
1059 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1060 gtk_table_set_row_spacings (GTK_TABLE (table), 3);
1062 ghid_table_coord_entry (table, 0, 0, NULL,
1063 PCB->Bloat, MIN_DRC_VALUE, MAX_DRC_VALUE,
1064 CE_SMALL, 0, coord_entry_cb,
1065 &PCB->Bloat, FALSE,
1066 _("Minimum copper spacing"));
1068 ghid_table_coord_entry (table, 1, 0, NULL,
1069 PCB->minWid, MIN_DRC_VALUE, MAX_DRC_VALUE,
1070 CE_SMALL, 0, coord_entry_cb,
1071 &PCB->minWid, FALSE,
1072 _("Minimum copper width"));
1074 ghid_table_coord_entry (table, 2, 0, NULL,
1075 PCB->Shrink, MIN_DRC_VALUE, MAX_DRC_VALUE,
1076 CE_SMALL, 0, coord_entry_cb,
1077 &PCB->Shrink, FALSE,
1078 _("Minimum touching copper overlap"));
1080 ghid_table_coord_entry (table, 3, 0, NULL,
1081 PCB->minSlk, MIN_DRC_VALUE, MAX_DRC_VALUE,
1082 CE_SMALL, 0, coord_entry_cb,
1083 &PCB->minSlk, FALSE,
1084 _("Minimum silk width"));
1086 ghid_table_coord_entry (table, 4, 0, NULL,
1087 PCB->minDrill, MIN_DRC_VALUE, MAX_DRC_VALUE,
1088 CE_SMALL, 0, coord_entry_cb,
1089 &PCB->minDrill, FALSE,
1090 _("Minimum drill diameter"));
1092 ghid_table_coord_entry (table, 5, 0, NULL,
1093 PCB->minRing, MIN_DRC_VALUE, MAX_DRC_VALUE,
1094 CE_SMALL, 0, coord_entry_cb,
1095 &PCB->minRing, FALSE,
1096 _("Minimum annular ring"));
1098 ghid_check_button_connected (vbox, &use_drc_sizes_default_button, FALSE,
1099 TRUE, FALSE, FALSE, 0, NULL, NULL,
1101 ("Use DRC values as the default for new layouts"));
1103 gtk_widget_show_all (config_sizes_vbox);
1107 /* -------------- The Increments config page ----------------
1109 /* Increment/decrement values are kept in mil and mm units and not in
1110 | PCB units.
1112 static GtkWidget *config_increments_vbox, *config_increments_tab_vbox;
1114 static void
1115 increment_spin_button_cb (GHidCoordEntry * ce, void * dst)
1117 *(Coord *)dst = ghid_coord_entry_get_value (ce);
1118 ghidgui->config_modified = TRUE;
1121 static void
1122 config_increments_tab_create (GtkWidget * tab_vbox)
1124 Increments *incr_mm = get_increments_struct (METRIC);
1125 Increments *incr_mil = get_increments_struct (IMPERIAL);
1126 GtkWidget *vbox, *hbox, *table;
1128 /* Need a vbox we can destroy if user changes grid units.
1130 if (!config_increments_vbox)
1132 vbox = gtk_vbox_new (FALSE, 0);
1133 gtk_box_pack_start (GTK_BOX (tab_vbox), vbox, FALSE, FALSE, 0);
1134 gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
1135 config_increments_vbox = vbox;
1136 config_increments_tab_vbox = tab_vbox;
1139 #define INCR_ENTRY(row, name, family, type, msg) \
1140 gtk_table_attach_defaults (GTK_TABLE (table), \
1141 gtk_label_new (name), \
1142 0, 1, row, row + 1); \
1143 ghid_table_coord_entry (table, row, 1, NULL, \
1144 incr_##family->type, \
1145 incr_##family->type##_min, \
1146 incr_##family->type##_max, \
1147 CE_SMALL, 0, increment_spin_button_cb, \
1148 &incr_##family->type, FALSE, \
1149 msg)
1151 /* ---- Metric Settings ---- */
1152 vbox = ghid_category_vbox (config_increments_vbox,
1153 _("Metric Increment Settings"), 4, 2, TRUE, TRUE);
1154 hbox = gtk_hbox_new (FALSE, 0);
1155 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1156 table = gtk_table_new (4, 3, FALSE);
1157 gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
1158 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1159 gtk_table_set_row_spacings (GTK_TABLE (table), 18);
1161 INCR_ENTRY (0, _("Grid:"), mm, grid,
1162 _("For 'g' and '<shift>g' grid change actions"));
1163 INCR_ENTRY (1, _("Size:"), mm, size,
1164 _("For 's' and '<shift>s' size change actions on lines,\n"
1165 "pads, pins and text.\n"
1166 "Use '<ctrl>s' and '<shift><ctrl>s' for drill holes."));
1167 INCR_ENTRY (2, _("Line:"), mm, line,
1168 _("For 'l' and '<shift>l' routing line width change actions"));
1169 INCR_ENTRY (3, _("Clear:"), mm, clear,
1170 _("For 'k' and '<shift>k' line clearance inside polygon size\n"
1171 "change actions"));
1173 vbox = ghid_category_vbox (config_increments_vbox,
1174 _("Imperial Increment Settings"), 4, 2, TRUE, TRUE);
1175 hbox = gtk_hbox_new (FALSE, 0);
1176 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1177 table = gtk_table_new (4, 3, FALSE);
1178 gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
1179 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1180 gtk_table_set_row_spacings (GTK_TABLE (table), 18);
1182 INCR_ENTRY (0, _("Grid:"), mil, grid,
1183 _("For 'g' and '<shift>g' grid change actions"));
1184 INCR_ENTRY (1, _("Size:"), mil, size,
1185 _("For 's' and '<shift>s' size change actions on lines,\n"
1186 "pads, pins and text.\n"
1187 "Use '<ctrl>s' and '<shift><ctrl>s' for drill holes."));
1188 INCR_ENTRY (2, _("Line:"), mil, line,
1189 _("For 'l' and '<shift>l' routing line width change actions"));
1190 INCR_ENTRY (3, _("Clear:"), mil, clear,
1191 _("For 'k' and '<shift>k' line clearance inside polygon size\n"
1192 "change actions"));
1193 #undef INCR_ENTRY
1195 gtk_widget_show_all (config_increments_vbox);
1198 /* -------------- The Library config page ----------------
1200 static GtkWidget *library_newlib_entry;
1202 static void
1203 config_library_apply (void)
1205 if (dup_string
1206 (&lib_newlib_config, ghid_entry_get_text (library_newlib_entry)))
1207 ghidgui->config_modified = TRUE;
1210 static void
1211 config_library_tab_create (GtkWidget * tab_vbox)
1213 GtkWidget *vbox, *label, *entry;
1215 gtk_container_set_border_width (GTK_CONTAINER (tab_vbox), 6);
1216 vbox = ghid_category_vbox (tab_vbox, _("Element Directories"),
1217 4, 2, TRUE, TRUE);
1218 label = gtk_label_new ("");
1219 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
1220 gtk_label_set_markup (GTK_LABEL (label),
1222 ("<small>Enter a \""
1223 PCB_PATH_DELIMETER
1224 "\" separated list of custom top level\n"
1225 "element directories. For example:\n"
1226 "\t<b>~/gaf/pcb-elements"
1227 PCB_PATH_DELIMETER
1228 "packages"
1229 PCB_PATH_DELIMETER
1230 "/usr/local/pcb-elements</b>\n"
1231 "Elements should be organized into subdirectories below each\n"
1232 "top level directory. Restart program for changes to take effect."
1233 "</small>"));
1235 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
1236 entry = gtk_entry_new ();
1237 library_newlib_entry = entry;
1238 gtk_entry_set_text (GTK_ENTRY (entry), lib_newlib_config);
1239 gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 4);
1243 /* -------------- The Layers Group config page ----------------
1245 static GtkWidget *config_groups_table, *config_groups_vbox, *config_groups_window;
1247 static GtkWidget *layer_entry[MAX_LAYER];
1248 static GtkWidget *group_button[MAX_LAYER + 2][MAX_LAYER];
1250 #if FIXME
1251 static GtkWidget *use_layer_default_button;
1252 #endif
1254 static gint config_layer_group[MAX_LAYER + 2];
1256 static LayerGroupType layer_groups, /* Working copy */
1257 *lg_monitor; /* Keep track if our working copy */
1258 /* needs to be changed (new layout) */
1260 static gboolean groups_modified, groups_holdoff, layers_applying;
1262 static gchar *layer_info_text[] = {
1263 N_("<h>Layer Names\n"),
1264 N_("You may enter layer names for the layers drawn on the screen.\n"
1265 "The special 'top side' and 'bottom side' are layers which\n"
1266 "will be printed out, so they must have in their group at least one\n"
1267 "of the other layers that are drawn on the screen.\n"),
1268 "\n",
1269 N_("<h>Layer Groups\n"),
1270 N_("Each layer on the screen may be in its own group which allows the\n"
1271 "maximum number of board layers. However, for boards with fewer\n"
1272 "layers, you may group layers together which will then print as a\n"
1273 "single layer on a printout. This allows a visual color distinction\n"
1274 "to be displayed on the screen for signal groups which will print as\n"
1275 "a single layer\n"),
1276 "\n",
1277 N_("For example, for a 4 layer board a useful layer group arrangement\n"
1278 "can be to have 3 screen displayed layers grouped into the same group\n"
1279 "as the 'top side' and 'bottom side' printout layers. Then\n"
1280 "groups such as signals, ground, and supply traces can be color\n"
1281 "coded on the screen while printing as a single layer. For this\n"
1282 "you would select buttons and enter names on the Setup page to\n"
1283 "structure four layer groups similar to this:\n"),
1284 "\n",
1285 N_("<b>Group 1:"),
1286 "\n\t",
1287 N_("top"),
1288 "\n\t",
1289 N_("GND-top"),
1290 "\n\t",
1291 N_("Vcc-top"),
1292 "\n\t",
1293 N_("top side"),
1294 "\n",
1295 N_("<b>Group 2:"),
1296 "\n\t",
1297 N_("bottom"),
1298 "\n\t",
1299 N_("GND-bottom"),
1300 "\n\t",
1301 N_("Vcc-bottom"),
1302 "\n\t",
1303 N_("bottom side"),
1304 "\n",
1305 N_("<b>Group 3:"),
1306 "\n\t",
1307 N_("signal1"),
1308 "\n",
1309 N_("<b>Group 4:"),
1310 "\n\t",
1311 N_("signal2"),
1312 "\n"
1315 static void
1316 config_layer_groups_radio_button_cb (GtkToggleButton * button, gpointer data)
1318 gint layer = GPOINTER_TO_INT (data) >> 8;
1319 gint group = GPOINTER_TO_INT (data) & 0xff;
1321 if (!gtk_toggle_button_get_active (button) || groups_holdoff)
1322 return;
1323 config_layer_group[layer] = group;
1324 groups_modified = TRUE;
1325 ghidgui->config_modified = TRUE;
1328 /* Construct a layer group string. Follow logic in WritePCBDataHeader(),
1329 | but use g_string functions.
1331 static gchar *
1332 make_layer_group_string (LayerGroupType * lg)
1334 GString *string;
1335 gint group, entry, layer;
1337 string = g_string_new ("");
1339 for (group = 0; group < max_group; group++)
1341 if (lg->Number[group] == 0)
1342 continue;
1343 for (entry = 0; entry < lg->Number[group]; entry++)
1345 layer = lg->Entries[group][entry];
1346 if (layer == component_silk_layer)
1347 string = g_string_append (string, "c");
1348 else if (layer == solder_silk_layer)
1349 string = g_string_append (string, "s");
1350 else
1351 g_string_append_printf (string, "%d", layer + 1);
1353 if (entry != lg->Number[group] - 1)
1354 string = g_string_append (string, ",");
1356 if (group != max_group - 1)
1357 string = g_string_append (string, ":");
1359 return g_string_free (string, FALSE); /* Don't free string->str */
1362 static void
1363 config_layers_apply (void)
1365 LayerType *layer;
1366 gchar *s;
1367 gint group, i;
1368 gint componentgroup = 0, soldergroup = 0;
1369 gboolean use_as_default = FALSE, layers_modified = FALSE;
1371 #if FIXME
1372 use_as_default =
1373 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
1374 (use_layer_default_button));
1375 #endif
1377 /* Get each layer name entry and dup if modified into the PCB layer names
1378 | and, if to use as default, the Settings layer names.
1380 for (i = 0; i < max_copper_layer; ++i)
1382 layer = &PCB->Data->Layer[i];
1383 s = ghid_entry_get_text (layer_entry[i]);
1384 if (dup_core_string (&layer->Name, s))
1385 layers_modified = TRUE;
1386 /* FIXME */
1387 if (use_as_default && dup_core_string (&Settings.DefaultLayerName[i], s))
1388 ghidgui->config_modified = TRUE;
1391 /* Layer names can be changed from the menus and that can update the
1392 | config. So holdoff the loop.
1394 layers_applying = TRUE;
1395 if (layers_modified)
1396 ghid_layer_buttons_update ();
1397 layers_applying = FALSE;
1399 if (groups_modified) /* If any group radio buttons were toggled. */
1401 /* clear all entries and read layer by layer
1403 for (group = 0; group < max_group; group++)
1404 layer_groups.Number[group] = 0;
1406 for (i = 0; i < max_copper_layer + 2; i++)
1408 group = config_layer_group[i] - 1;
1409 layer_groups.Entries[group][layer_groups.Number[group]++] = i;
1411 if (i == component_silk_layer)
1412 componentgroup = group;
1413 else if (i == solder_silk_layer)
1414 soldergroup = group;
1417 /* do some cross-checking
1418 | top-side and bottom-side must be in different groups
1419 | top-side and bottom-side must not be the only one in the group
1421 if (layer_groups.Number[soldergroup] <= 1
1422 || layer_groups.Number[componentgroup] <= 1)
1424 Message (_
1425 ("Both, 'top side' and 'bottom side' layer must have at least\n"
1426 "\tone other layer in their group.\n"));
1427 return;
1429 else if (soldergroup == componentgroup)
1431 Message (_
1432 ("The 'top side' and 'bottom side' layers are not allowed\n"
1433 "\tto be in the same layer group #\n"));
1434 return;
1436 PCB->LayerGroups = layer_groups;
1437 ghid_invalidate_all();
1438 groups_modified = FALSE;
1440 if (use_as_default)
1442 s = make_layer_group_string (&PCB->LayerGroups);
1443 if (dup_core_string (&Settings.Groups, s))
1445 ParseGroupString (Settings.Groups, &Settings.LayerGroups, max_copper_layer);
1446 ghidgui->config_modified = TRUE;
1448 g_free (s);
1452 static void
1453 config_layer_group_button_state_update (void)
1455 gint g, i;
1457 /* Set button active corresponding to layer group state.
1459 groups_holdoff = TRUE;
1460 for (g = 0; g < max_group; g++)
1461 for (i = 0; i < layer_groups.Number[g]; i++)
1463 /* printf("layer %d in group %d\n", layer_groups.Entries[g][i], g +1); */
1464 config_layer_group[layer_groups.Entries[g][i]] = g + 1;
1465 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
1466 (group_button
1467 [layer_groups.Entries[g][i]][g]),
1468 TRUE);
1470 groups_holdoff = FALSE;
1473 static void
1474 layer_name_entry_cb(GtkWidget *entry, gpointer data)
1476 gint i = GPOINTER_TO_INT(data);
1477 LayerType *layer;
1478 gchar *name;
1480 layer = &PCB->Data->Layer[i];
1481 name = ghid_entry_get_text(entry);
1482 if (dup_core_string (&layer->Name, name))
1483 ghid_layer_buttons_update();
1486 void
1487 ghid_config_groups_changed(void)
1489 GtkWidget *vbox, *table, *button, *label, *scrolled_window;
1490 GSList *group;
1491 gchar buf[32], *name;
1492 gint layer, i;
1494 if (!config_groups_vbox)
1495 return;
1496 vbox = config_groups_vbox;
1498 if (config_groups_table)
1499 gtk_widget_destroy(config_groups_table);
1500 if (config_groups_window)
1501 gtk_widget_destroy(config_groups_window);
1503 config_groups_window = scrolled_window =
1504 gtk_scrolled_window_new (NULL, NULL);
1505 gtk_widget_set_size_request (scrolled_window, 34, 408);
1506 gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 3);
1507 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
1508 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1509 gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
1510 gtk_widget_show (scrolled_window);
1513 table = gtk_table_new (max_copper_layer + 3, max_group + 1, FALSE);
1514 config_groups_table = table;
1515 gtk_table_set_row_spacings (GTK_TABLE (table), 3);
1516 gtk_scrolled_window_add_with_viewport (
1517 GTK_SCROLLED_WINDOW (scrolled_window), table);
1518 gtk_widget_show (table);
1520 layer_groups = PCB->LayerGroups; /* working copy */
1521 lg_monitor = &PCB->LayerGroups; /* So can know if PCB changes on us */
1523 label = gtk_label_new (_("Group #"));
1524 gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1);
1525 gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
1527 for (i = 1; i < max_group + 1; ++i)
1529 if (i < 10)
1530 snprintf (buf, sizeof (buf), " %d", i);
1531 else
1532 snprintf (buf, sizeof (buf), "%d", i);
1533 label = gtk_label_new (buf);
1534 gtk_table_attach_defaults (GTK_TABLE (table), label, i, i + 1, 0, 1);
1537 /* Create a row of radio toggle buttons for layer. So each layer
1538 | can have an active radio button set for the group it needs to be in.
1540 for (layer = 0; layer < max_copper_layer + 2; ++layer)
1542 if (layer == component_silk_layer)
1543 name = _("top side");
1544 else if (layer == solder_silk_layer)
1545 name = _("bottom side");
1546 else
1547 name = (gchar *) UNKNOWN (PCB->Data->Layer[layer].Name);
1549 if (layer >= max_copper_layer)
1551 label = gtk_label_new (name);
1552 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1553 gtk_table_attach_defaults (GTK_TABLE (table), label,
1554 0, 1, layer + 1, layer + 2);
1556 else
1558 layer_entry[layer] = gtk_entry_new ();
1559 gtk_entry_set_text (GTK_ENTRY (layer_entry[layer]), name);
1560 gtk_table_attach_defaults (GTK_TABLE (table), layer_entry[layer],
1561 0, 1, layer + 1, layer + 2);
1562 g_signal_connect(G_OBJECT(layer_entry[layer]), "activate",
1563 G_CALLBACK(layer_name_entry_cb), GINT_TO_POINTER(layer));
1566 group = NULL;
1567 for (i = 0; i < max_group; ++i)
1569 snprintf (buf, sizeof (buf), "%2.2d", i+1);
1570 button = gtk_radio_button_new_with_label (group, buf);
1572 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE);
1573 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
1574 gtk_table_attach_defaults (GTK_TABLE (table), button,
1575 i + 1, i + 2, layer + 1, layer + 2);
1576 g_signal_connect (G_OBJECT (button), "toggled",
1577 G_CALLBACK (config_layer_groups_radio_button_cb),
1578 GINT_TO_POINTER ((layer << 8) | (i + 1)));
1579 group_button[layer][i] = button;
1582 gtk_widget_show_all(config_groups_vbox);
1583 config_layer_group_button_state_update ();
1587 static void
1588 edit_layer_button_cb(GtkWidget *widget, gchar *data)
1590 gchar **argv;
1592 if (PCB->RatDraw || PCB->SilkActive)
1593 return;
1595 argv = g_strsplit(data, ",", -1);
1596 MoveLayerAction(2, argv, 0, 0);
1597 g_strfreev(argv);
1600 static void
1601 config_layers_tab_create (GtkWidget * tab_vbox)
1603 GtkWidget *tabs, *vbox, *vbox1, *button, *text, *sep;
1604 GtkWidget *hbox, *arrow;
1605 gint i;
1607 tabs = gtk_notebook_new ();
1608 gtk_box_pack_start (GTK_BOX (tab_vbox), tabs, TRUE, TRUE, 0);
1610 /* -- Change tab */
1611 vbox = ghid_notebook_page(tabs, _("Change"), 0, 6);
1612 vbox1 = ghid_category_vbox(vbox,
1613 _("Operations on currently selected layer:"),
1614 4, 2, TRUE, TRUE);
1616 button = gtk_button_new();
1617 arrow = gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_ETCHED_IN);
1618 gtk_container_add(GTK_CONTAINER(button), arrow);
1619 g_signal_connect(G_OBJECT(button), (gchar *)"clicked",
1620 G_CALLBACK(edit_layer_button_cb), (gchar *)"c,up");
1621 hbox = gtk_hbox_new(FALSE, 0);
1622 gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
1623 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1625 button = gtk_button_new();
1626 arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_ETCHED_IN);
1627 gtk_container_add(GTK_CONTAINER(button), arrow);
1628 g_signal_connect(G_OBJECT(button), (gchar *)"clicked",
1629 G_CALLBACK(edit_layer_button_cb), (gchar *)"c,down");
1630 hbox = gtk_hbox_new(FALSE, 0);
1631 gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
1632 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1634 button = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1635 g_signal_connect(G_OBJECT(button), (gchar *)"clicked",
1636 G_CALLBACK(edit_layer_button_cb), (gchar *)"c,-1");
1637 hbox = gtk_hbox_new(FALSE, 0);
1638 gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
1639 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1641 vbox1 = ghid_category_vbox(vbox,
1642 _("Add new layer above currently selected layer:"),
1643 4, 2, TRUE, TRUE);
1644 button = gtk_button_new_from_stock(GTK_STOCK_ADD);
1645 g_signal_connect(G_OBJECT(button), (gchar *)"clicked",
1646 G_CALLBACK(edit_layer_button_cb), (gchar *)"-1,c");
1647 hbox = gtk_hbox_new(FALSE, 0);
1648 gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
1649 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1651 /* -- Groups tab */
1652 vbox = ghid_notebook_page (tabs, _("Groups"), 0, 6);
1653 config_groups_vbox = gtk_vbox_new(FALSE, 0);
1654 gtk_box_pack_start(GTK_BOX(vbox), config_groups_vbox, FALSE, FALSE, 0);
1655 ghid_config_groups_changed();
1657 sep = gtk_hseparator_new ();
1658 gtk_box_pack_start (GTK_BOX (vbox), sep, FALSE, FALSE, 4);
1660 #if FIXME
1661 ghid_check_button_connected (vbox, &use_layer_default_button, FALSE,
1662 TRUE, FALSE, FALSE, 8, NULL, NULL,
1663 ("Use these layer settings as the default for new layouts"));
1664 #endif
1667 /* -- Info tab */
1668 vbox = ghid_notebook_page (tabs, _("Info"), 0, 6);
1670 text = ghid_scrolled_text_view (vbox, NULL,
1671 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1672 for (i = 0; i < sizeof (layer_info_text) / sizeof (gchar *); ++i)
1673 ghid_text_view_append (text, _(layer_info_text[i]));
1677 void
1678 ghid_config_layer_name_update (gchar * name, gint layer)
1680 if (!config_window || layers_applying || !name)
1681 return;
1682 gtk_entry_set_text (GTK_ENTRY (layer_entry[layer]), name);
1684 /* If we get a config layer name change because a new PCB is loaded
1685 | or new layout started, need to change our working layer group copy.
1687 if (lg_monitor != &PCB->LayerGroups)
1689 layer_groups = PCB->LayerGroups;
1690 lg_monitor = &PCB->LayerGroups;
1691 config_layer_group_button_state_update ();
1692 groups_modified = FALSE;
1696 /* -------------- The Colors config page ----------------
1698 static GtkWidget *config_colors_vbox,
1699 *config_colors_tab_vbox,
1700 *config_colors_save_button,
1701 *config_color_file_label, *config_color_warn_label;
1703 static void config_colors_tab_create (GtkWidget * tab_vbox);
1705 static gboolean config_colors_modified;
1707 static void
1708 config_color_file_set_label (void)
1710 gchar *str, *name;
1712 if (!*color_file)
1713 name = g_strdup ("defaults");
1714 else
1715 name = g_path_get_basename (color_file);
1717 str = g_strdup_printf (_("Current colors loaded: <b>%s</b>"), name);
1718 gtk_label_set_markup (GTK_LABEL (config_color_file_label), str);
1719 g_free (name);
1720 g_free (str);
1723 static void
1724 config_color_defaults_cb (gpointer data)
1726 GList *list;
1727 ConfigColor *cc;
1728 HID_Attribute *ha;
1730 for (list = config_color_list; list; list = list->next)
1732 cc = (ConfigColor *) list->data;
1733 ha = cc->attributes;
1734 dup_core_string ((char **) ha->value, ha->default_val.str_value);
1735 cc->color_is_mapped = FALSE;
1736 ghid_set_special_colors (ha);
1739 dup_string (&color_file, "");
1740 ghidgui->config_modified = TRUE;
1742 gtk_widget_set_sensitive (config_colors_save_button, FALSE);
1743 gtk_widget_set_sensitive (config_color_warn_label, FALSE);
1744 config_color_file_set_label ();
1745 config_colors_modified = FALSE;
1747 ghid_layer_buttons_color_update ();
1749 /* Receate the colors config page to pick up new colors.
1751 gtk_widget_destroy (config_colors_vbox);
1752 config_colors_tab_create (config_colors_tab_vbox);
1754 ghid_invalidate_all();
1757 static void
1758 config_color_load_cb (gpointer data)
1760 gchar *path, *dir = g_strdup (color_dir);
1762 path = ghid_dialog_file_select_open (_("Load Color File"), &dir, NULL);
1763 if (path)
1765 config_colors_read (path);
1766 dup_string (&color_file, path);
1767 ghidgui->config_modified = TRUE;
1769 gtk_widget_set_sensitive (config_colors_save_button, FALSE);
1770 gtk_widget_set_sensitive (config_color_warn_label, FALSE);
1771 config_color_file_set_label ();
1772 config_colors_modified = FALSE;
1774 g_free (path);
1775 g_free (dir);
1777 /* Receate the colors config page to pick up new colors.
1779 gtk_widget_destroy (config_colors_vbox);
1780 config_colors_tab_create (config_colors_tab_vbox);
1782 ghid_layer_buttons_color_update ();
1783 ghid_invalidate_all();
1786 static void
1787 config_color_save_cb (gpointer data)
1789 gchar *name, *path, *dir = g_strdup (color_dir);
1791 path =
1792 ghid_dialog_file_select_save (_("Save Color File"), &dir, NULL, NULL);
1793 if (path)
1795 name = g_path_get_basename (path);
1796 if (!strcmp (name, "default"))
1797 ghid_dialog_message (_
1798 ("Sorry, not overwriting the default color file!"));
1799 else
1801 config_colors_write (path);
1802 dup_string (&color_file, path);
1803 ghidgui->config_modified = TRUE;
1805 gtk_widget_set_sensitive (config_colors_save_button, FALSE);
1806 gtk_widget_set_sensitive (config_color_warn_label, FALSE);
1807 config_color_file_set_label ();
1808 config_colors_modified = FALSE;
1810 g_free (name);
1812 g_free (path);
1813 g_free (dir);
1816 static void
1817 config_color_set_cb (GtkWidget * button, ConfigColor * cc)
1819 GdkColor new_color;
1820 HID_Attribute *ha = cc->attributes;
1821 gchar *str;
1823 gtk_color_button_get_color (GTK_COLOR_BUTTON (button), &new_color);
1824 str = ghid_get_color_name (&new_color);
1825 ghid_map_color_string (str, &cc->color);
1826 *(char **) ha->value = str;
1827 /* g_free(str); Memory leak */
1829 config_colors_modified = TRUE;
1830 gtk_widget_set_sensitive (config_colors_save_button, TRUE);
1831 gtk_widget_set_sensitive (config_color_warn_label, TRUE);
1833 ghid_set_special_colors (ha);
1834 ghid_layer_buttons_color_update ();
1835 ghid_invalidate_all();
1838 static void
1839 config_color_button_create (GtkWidget * box, ConfigColor * cc)
1841 GtkWidget *button, *hbox, *label;
1842 HID_Attribute *ha = cc->attributes;
1843 gchar *title;
1845 hbox = gtk_hbox_new (FALSE, 6);
1846 gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 0);
1848 if (!cc->color_is_mapped)
1849 ghid_map_color_string (*(char **) ha->value, &cc->color);
1850 cc->color_is_mapped = TRUE;
1852 title = g_strdup_printf (_("PCB %s Color"), ha->name);
1853 button = gtk_color_button_new_with_color (&cc->color);
1854 gtk_color_button_set_title (GTK_COLOR_BUTTON (button), title);
1855 g_free (title);
1857 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1858 label = gtk_label_new (ha->name);
1859 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1860 g_signal_connect (G_OBJECT (button), "color-set",
1861 G_CALLBACK (config_color_set_cb), cc);
1864 static void
1865 config_colors_tab_create (GtkWidget * tab_vbox)
1867 GtkWidget *scrolled_vbox, *vbox, *hbox, *expander, *sep;
1868 GList *list;
1869 ConfigColor *cc;
1871 vbox = gtk_vbox_new (FALSE, 0);
1872 gtk_box_pack_start (GTK_BOX (tab_vbox), vbox, TRUE, TRUE, 0);
1873 gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
1875 config_colors_vbox = vbox; /* can be destroyed if color file loaded */
1876 config_colors_tab_vbox = tab_vbox;
1878 scrolled_vbox = ghid_scrolled_vbox (config_colors_vbox, NULL,
1879 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1881 /* ---- Main colors ---- */
1882 expander = gtk_expander_new (_("Main colors"));
1883 gtk_box_pack_start (GTK_BOX (scrolled_vbox), expander, FALSE, FALSE, 2);
1884 vbox = gtk_vbox_new (FALSE, 0);
1885 gtk_container_add (GTK_CONTAINER (expander), vbox);
1886 vbox = ghid_category_vbox (vbox, NULL, 0, 2, TRUE, FALSE);
1888 for (list = config_color_list; list; list = list->next)
1890 cc = (ConfigColor *) list->data;
1891 if (cc->type != MISC_COLOR)
1892 continue;
1893 config_color_button_create (vbox, cc);
1896 /* ---- Layer colors ---- */
1897 expander = gtk_expander_new (_("Layer colors"));
1898 gtk_box_pack_start (GTK_BOX (scrolled_vbox), expander, FALSE, FALSE, 2);
1899 vbox = gtk_vbox_new (FALSE, 0);
1900 gtk_container_add (GTK_CONTAINER (expander), vbox);
1901 vbox = ghid_category_vbox (vbox, NULL, 0, 2, TRUE, FALSE);
1903 for (list = config_color_list; list; list = list->next)
1905 cc = (ConfigColor *) list->data;
1906 if (cc->type != LAYER_COLOR)
1907 continue;
1908 config_color_button_create (vbox, cc);
1911 /* ---- Selected colors ---- */
1912 expander = gtk_expander_new (_("Selected colors"));
1913 gtk_box_pack_start (GTK_BOX (scrolled_vbox), expander, FALSE, FALSE, 2);
1914 vbox = gtk_vbox_new (FALSE, 0);
1915 gtk_container_add (GTK_CONTAINER (expander), vbox);
1916 vbox = ghid_category_vbox (vbox, NULL, 0, 2, TRUE, FALSE);
1918 for (list = config_color_list; list; list = list->next)
1920 cc = (ConfigColor *) list->data;
1921 if (cc->type != MISC_SELECTED_COLOR)
1922 continue;
1923 config_color_button_create (vbox, cc);
1925 sep = gtk_hseparator_new ();
1926 gtk_box_pack_start (GTK_BOX (vbox), sep, FALSE, FALSE, 2);
1927 for (list = config_color_list; list; list = list->next)
1929 cc = (ConfigColor *) list->data;
1930 if (cc->type != LAYER_SELECTED_COLOR)
1931 continue;
1932 config_color_button_create (vbox, cc);
1935 config_color_warn_label = gtk_label_new ("");
1936 gtk_label_set_use_markup (GTK_LABEL (config_color_warn_label), TRUE);
1937 gtk_label_set_markup (GTK_LABEL (config_color_warn_label),
1938 _("<b>Warning:</b> unsaved color changes will be lost"
1939 " at program exit."));
1940 gtk_box_pack_start (GTK_BOX (config_colors_vbox), config_color_warn_label,
1941 FALSE, FALSE, 4);
1943 hbox = gtk_hbox_new (FALSE, 0);
1944 gtk_box_pack_start (GTK_BOX (config_colors_vbox), hbox, FALSE, FALSE, 6);
1946 config_color_file_label = gtk_label_new ("");
1947 gtk_label_set_use_markup (GTK_LABEL (config_color_file_label), TRUE);
1948 config_color_file_set_label ();
1949 gtk_box_pack_start (GTK_BOX (hbox), config_color_file_label,
1950 FALSE, FALSE, 0);
1952 ghid_button_connected (hbox, NULL, FALSE, FALSE, FALSE, 4,
1953 config_color_load_cb, NULL, _("Load"));
1954 ghid_button_connected (hbox, &config_colors_save_button,
1955 FALSE, FALSE, FALSE, 4,
1956 config_color_save_cb, NULL, _("Save"));
1957 ghid_button_connected (hbox, NULL, FALSE, FALSE, FALSE, 4,
1958 config_color_defaults_cb, NULL, _("Defaults"));
1960 gtk_widget_set_sensitive (config_colors_save_button,
1961 config_colors_modified);
1962 gtk_widget_set_sensitive (config_color_warn_label, config_colors_modified);
1963 gtk_widget_show_all (config_colors_vbox);
1967 /* --------------- The main config page -----------------
1969 enum
1971 CONFIG_NAME_COLUMN,
1972 CONFIG_PAGE_COLUMN,
1973 N_CONFIG_COLUMNS
1976 static GtkNotebook *config_notebook;
1978 static GtkWidget *
1979 config_page_create (GtkTreeStore * tree, GtkTreeIter * iter,
1980 GtkNotebook * notebook)
1982 GtkWidget *vbox;
1983 gint page;
1985 vbox = gtk_vbox_new (FALSE, 0);
1986 gtk_notebook_append_page (notebook, vbox, NULL);
1987 page = gtk_notebook_get_n_pages (notebook) - 1;
1988 gtk_tree_store_set (tree, iter, CONFIG_PAGE_COLUMN, page, -1);
1989 return vbox;
1992 void
1993 ghid_config_handle_units_changed (void)
1995 gchar *text = pcb_g_strdup_printf ("<b>%s</b>",
1996 Settings.grid_unit->in_suffix);
1997 ghid_set_cursor_position_labels ();
1998 gtk_label_set_markup (GTK_LABEL (ghidgui->grid_units_label), text);
1999 g_free (text);
2001 if (config_sizes_vbox)
2003 gtk_widget_destroy (config_sizes_vbox);
2004 config_sizes_vbox = NULL;
2005 config_sizes_tab_create (config_sizes_tab_vbox);
2007 if (config_increments_vbox)
2009 gtk_widget_destroy (config_increments_vbox);
2010 config_increments_vbox = NULL;
2011 config_increments_tab_create (config_increments_tab_vbox);
2013 ghidgui->config_modified = TRUE;
2016 void
2017 ghid_config_text_scale_update (void)
2019 if (config_window)
2020 gtk_spin_button_set_value (GTK_SPIN_BUTTON (config_text_spin_button),
2021 (gdouble) Settings.TextScale);
2024 static void
2025 config_close_cb (gpointer data)
2027 /* Config pages may need to check for modified entries, use as default
2028 | options, etc when the config window is closed.
2030 config_sizes_apply ();
2031 config_layers_apply ();
2032 config_library_apply ();
2033 config_general_apply ();
2035 config_sizes_vbox = NULL;
2036 config_increments_vbox = NULL;
2038 config_groups_vbox = config_groups_table = NULL;
2039 config_groups_window = NULL;
2041 gtk_widget_destroy (config_window);
2042 config_window = NULL;
2045 static void
2046 config_destroy_cb (gpointer data)
2048 config_sizes_vbox = NULL;
2049 config_increments_vbox = NULL;
2050 config_groups_vbox = config_groups_table = NULL;
2051 config_groups_window = NULL;
2052 gtk_widget_destroy (config_window);
2053 config_window = NULL;
2056 static void
2057 config_selection_changed_cb (GtkTreeSelection * selection, gpointer data)
2059 GtkTreeIter iter;
2060 GtkTreeModel *model;
2061 gint page;
2063 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
2064 return;
2065 gtk_tree_model_get (model, &iter, CONFIG_PAGE_COLUMN, &page, -1);
2066 gtk_notebook_set_current_page (config_notebook, page);
2069 void
2070 ghid_config_window_show (void)
2072 GtkWidget *widget, *main_vbox, *vbox, *config_hbox, *hbox;
2073 GtkWidget *scrolled;
2074 GtkWidget *button;
2075 GtkTreeStore *model;
2076 GtkTreeView *treeview;
2077 GtkTreeIter iter;
2078 GtkCellRenderer *renderer;
2079 GtkTreeViewColumn *column;
2080 GtkTreeSelection *select;
2082 if (config_window)
2084 gtk_window_present (GTK_WINDOW (config_window));
2085 return;
2088 config_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2089 g_signal_connect (G_OBJECT (config_window), "delete_event",
2090 G_CALLBACK (config_destroy_cb), NULL);
2092 gtk_window_set_title (GTK_WINDOW (config_window), _("PCB Preferences"));
2093 gtk_window_set_wmclass (GTK_WINDOW (config_window), "Pcb_Conf", "PCB");
2094 gtk_container_set_border_width (GTK_CONTAINER (config_window), 2);
2096 config_hbox = gtk_hbox_new (FALSE, 4);
2097 gtk_container_add (GTK_CONTAINER (config_window), config_hbox);
2099 scrolled = gtk_scrolled_window_new (NULL, NULL);
2100 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
2101 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
2102 gtk_box_pack_start (GTK_BOX (config_hbox), scrolled, FALSE, FALSE, 0);
2104 main_vbox = gtk_vbox_new (FALSE, 4);
2105 gtk_box_pack_start (GTK_BOX (config_hbox), main_vbox, TRUE, TRUE, 0);
2107 widget = gtk_notebook_new ();
2108 gtk_box_pack_start (GTK_BOX (main_vbox), widget, TRUE, TRUE, 0);
2109 config_notebook = GTK_NOTEBOOK (widget);
2110 gtk_notebook_set_show_tabs (config_notebook, FALSE);
2112 model = gtk_tree_store_new (N_CONFIG_COLUMNS, G_TYPE_STRING, G_TYPE_INT);
2115 /* -- General -- */
2116 gtk_tree_store_append (model, &iter, NULL);
2117 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("General"), -1);
2118 vbox = config_page_create (model, &iter, config_notebook);
2119 config_general_tab_create (vbox);
2122 /* -- Sizes -- */
2123 gtk_tree_store_append (model, &iter, NULL);
2124 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("Sizes"), -1);
2125 vbox = config_page_create (model, &iter, config_notebook);
2126 config_sizes_tab_create (vbox);
2128 /* -- Increments -- */
2129 gtk_tree_store_append (model, &iter, NULL);
2130 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("Increments"), -1);
2131 vbox = config_page_create (model, &iter, config_notebook);
2132 config_increments_tab_create (vbox);
2134 /* -- Library -- */
2135 gtk_tree_store_append (model, &iter, NULL);
2136 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("Library"), -1);
2137 vbox = config_page_create (model, &iter, config_notebook);
2138 config_library_tab_create (vbox);
2140 /* -- Layer names and groups -- */
2141 gtk_tree_store_append (model, &iter, NULL);
2142 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("Layers"), -1);
2143 vbox = config_page_create (model, &iter, config_notebook);
2144 config_layers_tab_create (vbox);
2147 /* -- Colors -- */
2148 gtk_tree_store_append (model, &iter, NULL);
2149 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("Colors"), -1);
2150 vbox = config_page_create (model, &iter, config_notebook);
2151 config_colors_tab_create (vbox);
2154 /* Create the tree view
2156 treeview =
2157 GTK_TREE_VIEW (gtk_tree_view_new_with_model (GTK_TREE_MODEL (model)));
2158 g_object_unref (G_OBJECT (model)); /* Don't need the model anymore */
2160 renderer = gtk_cell_renderer_text_new ();
2161 column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
2162 "text",
2163 CONFIG_NAME_COLUMN,
2164 NULL);
2165 gtk_tree_view_append_column (treeview, column);
2166 gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (treeview));
2169 select = gtk_tree_view_get_selection (treeview);
2170 gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
2171 g_signal_connect (G_OBJECT (select), "changed",
2172 G_CALLBACK (config_selection_changed_cb), NULL);
2175 hbox = gtk_hbutton_box_new ();
2176 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
2177 gtk_box_set_spacing (GTK_BOX (hbox), 5);
2178 gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
2180 button = gtk_button_new_from_stock (GTK_STOCK_OK);
2181 gtk_widget_set_can_default (button, TRUE);
2182 g_signal_connect (G_OBJECT (button), "clicked",
2183 G_CALLBACK (config_close_cb), NULL);
2184 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
2185 gtk_widget_grab_default (button);
2187 gtk_widget_show_all (config_window);