Add support for filling / thindrawing raw polygons to the HID interface
[geda-pcb/gde.git] / src / hid / gtk / gui-config.c
blob1b50d328e538423d007b9538ea00c1008fcdb560
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996 Thomas Nau
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 /* This file written by Bill Wilson for the PCB Gtk port.
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
33 #ifdef HAVE_STDLIB_H
34 #include <stdlib.h>
35 #endif
37 #include "gui.h"
38 #include "hid.h"
39 #include "../hidint.h"
40 #include "gtkhid.h"
42 #include "global.h"
43 #include "action.h"
44 #include "change.h"
45 #include "file.h"
46 #include "error.h"
47 #include "draw.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);
60 RCSID ("$Id$");
62 enum ConfigType
64 CONFIG_Boolean,
65 CONFIG_Integer,
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 {"gui-title-window", CONFIG_Boolean, &_ghidgui.ghid_title_window},
123 {"use-command-window", CONFIG_Boolean, &_ghidgui.use_command_window},
124 {"save-in-tmp", CONFIG_Unused, NULL},
125 {"grid-units-mm", CONFIG_Unused, NULL},
127 {"history-size", CONFIG_Integer, &_ghidgui.history_size},
128 {"auto-pan-speed", CONFIG_Integer, &_ghidgui.auto_pan_speed},
129 {"top-window-width", CONFIG_Integer, &_ghidgui.top_window_width},
130 {"top-window-height", CONFIG_Integer, &_ghidgui.top_window_height},
131 {"log-window-width", CONFIG_Integer, &_ghidgui.log_window_width},
132 {"log-window-height", CONFIG_Integer, &_ghidgui.log_window_height},
133 {"library-window-width", CONFIG_Integer, &_ghidgui.library_window_width},
134 {"library-window-height", CONFIG_Integer, &_ghidgui.library_window_height},
135 {"netlist-window-height", CONFIG_Integer, &_ghidgui.netlist_window_height},
136 {"keyref-window-width", CONFIG_Integer, &_ghidgui.keyref_window_width},
137 {"keyref-window-height", CONFIG_Integer, &_ghidgui.keyref_window_height},
138 {"text-scale", CONFIG_Unused, NULL},
139 {"via-thickness", CONFIG_Unused, NULL},
140 {"via-drilling-hole", CONFIG_Unused, NULL},
141 {"backup-interval", CONFIG_Unused, NULL},
142 {"line-thickness", CONFIG_Unused, NULL},
143 {"rat-thickness", CONFIG_Unused, NULL},
144 {"bloat", CONFIG_Unused, NULL},
145 {"shrink", CONFIG_Unused, NULL},
146 {"min-width", CONFIG_Unused, NULL},
147 {"min-silk", CONFIG_Unused, NULL},
148 {"min-drill", CONFIG_Unused, NULL},
149 {"min-ring", CONFIG_Unused, NULL},
150 {"default-PCB-width", CONFIG_Unused, NULL},
151 {"default-PCB-height", CONFIG_Unused, NULL},
153 {"grid-increment-mil", CONFIG_Unused, NULL},
154 {"grid-increment-mm", CONFIG_Unused, NULL},
155 {"size-increment-mil", CONFIG_Unused, NULL},
156 {"size-increment-mm", CONFIG_Unused, NULL},
157 {"line-increment-mil", CONFIG_Unused, NULL},
158 {"line-increment-mm", CONFIG_Unused, NULL},
159 {"clear-increment-mil", CONFIG_Unused, NULL},
160 {"clear-increment-mm", CONFIG_Unused, NULL},
162 {"groups", CONFIG_Unused, NULL},
163 {"route-styles", CONFIG_Unused, NULL},
164 {"library-newlib", CONFIG_String, &lib_newlib_config},
165 {"color-file", CONFIG_String, &color_file},
166 /* FIXME: construct layer-names- in a list */
167 {"layer-name-1", CONFIG_Unused, NULL},
168 {"layer-name-2", CONFIG_Unused, NULL},
169 {"layer-name-3", CONFIG_Unused, NULL},
170 {"layer-name-4", CONFIG_Unused, NULL},
171 {"layer-name-5", CONFIG_Unused, NULL},
172 {"layer-name-6", CONFIG_Unused, NULL},
173 {"layer-name-7", CONFIG_Unused, NULL},
174 {"layer-name-8", CONFIG_Unused, NULL},
178 static FILE *
179 config_file_open (gchar * mode)
181 FILE *f;
182 gchar *homedir, *fname;
185 homedir = (gchar *) g_get_home_dir ();
186 if (!homedir)
188 g_message ("config_file_open: Can't get home directory!");
189 return NULL;
192 if (!config_dir)
194 config_dir =
195 g_build_path (G_DIR_SEPARATOR_S, homedir, PCB_CONFIG_DIR, NULL);
196 if (!g_file_test (config_dir, G_FILE_TEST_IS_DIR)
197 && mkdir (config_dir, 0755) < 0)
199 g_message ("config_file_open: Can't make \"%s\" directory!",
200 config_dir);
201 g_free (config_dir);
202 config_dir = NULL;
203 return NULL;
207 if (!color_dir) /* Convenient to make the color dir here */
209 color_dir =
210 g_build_path (G_DIR_SEPARATOR_S, config_dir, PCB_COLORS_DIR, NULL);
211 if (!g_file_test (color_dir, G_FILE_TEST_IS_DIR))
213 if (mkdir (color_dir, 0755) < 0)
215 g_message ("config_file_open: Can't make \"%s\" directory!",
216 color_dir);
217 g_free (color_dir);
218 color_dir = NULL;
220 fname = g_build_path (G_DIR_SEPARATOR_S,
221 color_dir, "Default", NULL);
222 dup_string (&color_file, fname);
223 g_free (fname);
227 fname = g_build_path (G_DIR_SEPARATOR_S, config_dir, PCB_CONFIG_FILE, NULL);
228 f = fopen (fname, mode);
230 g_free (fname);
231 return f;
234 static ConfigAttribute *
235 lookup_config_attribute (gchar * name, gboolean if_null_value)
237 ConfigAttribute *ca;
239 for (ca = &config_attributes[0];
240 ca < &config_attributes[0] + G_N_ELEMENTS (config_attributes); ++ca)
242 if (name && (!strcmp (name, ca->name)))
244 if (ca->value && if_null_value)
245 break;
246 return ca;
249 return NULL;
252 void
253 ghid_config_init (void)
255 HID_AttrNode *ha;
256 HID_Attribute *a;
257 ConfigAttribute *ca, dummy_attribute;
258 ConfigColor *cc;
259 gint len;
261 ghidgui->n_mode_button_columns = 3;
262 ghidgui->small_label_markup = TRUE;
263 ghidgui->auto_pan_on = TRUE;
264 ghidgui->auto_pan_speed = 3;
265 ghidgui->history_size = 5;
266 dup_string (&color_file, "");
268 for (ha = hid_attr_nodes; ha; ha = ha->next)
270 for (a = ha->attributes; a < ha->attributes + ha->n; ++a)
272 if (!a->value)
273 continue;
274 if ((ca = lookup_config_attribute (a->name, TRUE)) == NULL)
275 ca = &dummy_attribute;
276 ca->value = a->value; /* Typically &Setting.xxx */
277 ca->type = CONFIG_Unused;
278 switch (a->type)
280 case HID_Boolean:
281 *(char *) a->value = a->default_val.int_value;
282 ca->type = CONFIG_Boolean;
283 break;
284 case HID_Integer:
285 *(int *) a->value = a->default_val.int_value;
286 ca->type = CONFIG_Integer;
287 break;
288 case HID_Real:
289 *(double *) a->value = a->default_val.real_value;
290 ca->type = CONFIG_Real;
291 break;
293 case HID_String:
294 if (!a->name)
295 break;
296 *(char **) a->value = g_strdup (a->default_val.str_value);
297 ca->type = CONFIG_String;
299 len = strlen (a->name);
300 if (len < 7 || strstr (a->name, "color") == NULL)
301 break;
303 cc = g_new0 (ConfigColor, 1);
304 cc->attributes = a;
306 if (!strncmp (a->name, "layer-color", 11))
307 cc->type = LAYER_COLOR;
308 else if (!strncmp (a->name, "layer-selected-color", 20))
309 cc->type = LAYER_SELECTED_COLOR;
310 else if (!strncmp (a->name + len - 14, "selected-color", 14))
311 cc->type = MISC_SELECTED_COLOR;
312 else
313 cc->type = MISC_COLOR;
315 config_color_list = g_list_append (config_color_list, cc);
316 break;
318 case HID_Enum:
319 *(int *) a->value = a->default_val.int_value;
320 break;
322 case HID_Label:
323 case HID_Mixed:
324 case HID_Path:
325 break;
326 default:
327 abort ();
333 static gint
334 parse_option_line (gchar * line, gchar ** option_result, gchar ** arg_result)
336 gchar *s, *ss, option[64], arg[512];
337 gint argc = 1;
339 if (option_result)
340 *option_result = NULL;
341 if (arg_result)
342 *arg_result = NULL;
344 s = line;
345 while (*s == ' ' || *s == '\t')
346 ++s;
347 if (!*s || *s == '\n' || *s == '#' || *s == '[')
348 return 0;
349 if ((ss = strchr (s, '\n')) != NULL)
350 *ss = '\0';
351 arg[0] = '\0';
352 sscanf (s, "%63s %511[^\n]", option, arg);
354 s = option; /* Strip trailing ':' or '=' */
355 while (*s && *s != ':' && *s != '=')
356 ++s;
357 *s = '\0';
359 s = arg; /* Strip leading ':', '=', and whitespace */
360 while (*s == ' ' || *s == '\t' || *s == ':' || *s == '=' || *s == '"')
361 ++s;
362 if ((ss = strchr (s, '"')) != NULL)
363 *ss = '\0';
365 if (option_result)
366 *option_result = g_strdup (option);
367 if (arg_result && *s)
369 *arg_result = g_strdup (s);
370 ++argc;
372 return argc;
375 static gboolean
376 set_config_attribute (gchar * option, gchar * arg)
378 ConfigAttribute *ca;
379 #if 0
380 struct lconv *lc;
381 gchar locale_point, *comma_point, *period_point;
383 /* Until LC_NUMERIC is totally resolved, check if we need to decimal
384 | point convert. Ultimately, data files will be POSIX and gui
385 | presentation (hence the config file reals) will be in the users locale.
387 lc = localeconv ();
388 locale_point = *lc->decimal_point;
389 #endif
391 if ((ca = lookup_config_attribute (option, FALSE)) == NULL)
392 return FALSE;
393 switch (ca->type)
395 case CONFIG_Boolean:
396 *(gchar *) ca->value = (gchar) atoi (arg);
397 break;
399 case CONFIG_Integer:
400 *(gint *) ca->value = atoi (arg);
401 break;
403 case CONFIG_Real:
404 /* Hopefully temporary locale decimal point check:
406 #if 0
407 comma_point = strrchr (arg, ',');
408 period_point = strrchr (arg, '.');
409 if (comma_point && *comma_point != locale_point)
410 *comma_point = locale_point;
411 else if (period_point && *period_point != locale_point)
412 *period_point = locale_point;
413 #endif
414 *(double *) ca->value = atof (arg);
415 break;
417 case CONFIG_String:
418 dup_string ((char **) ca->value, arg ? arg : "");
419 break;
420 default:
421 break;
423 return TRUE;
426 static void
427 config_file_read (void)
429 FILE *f;
430 gchar buf[512], *option, *arg;
432 if ((f = config_file_open ("r")) == NULL)
433 return;
435 buf[0] = '\0';
436 while (fgets (buf, sizeof (buf), f))
438 if (parse_option_line (buf, &option, &arg) > 0)
439 set_config_attribute (option, arg);
440 g_free (option);
441 g_free (arg);
444 fclose (f);
447 static void
448 config_colors_write (gchar * path)
450 FILE *f;
451 GList *list;
452 HID_Attribute *ha;
453 ConfigColor *cc;
455 if ((f = fopen (path, "w")) == NULL)
456 return;
457 for (list = config_color_list; list; list = list->next)
459 cc = (ConfigColor *) list->data;
460 ha = cc->attributes;
461 fprintf (f, "%s =\t%s\n", ha->name, *(char **) ha->value);
463 fclose (f);
466 static gboolean
467 config_colors_read (gchar * path)
469 FILE *f;
470 GList *list;
471 ConfigColor *cc;
472 HID_Attribute *ha;
473 gchar *s, buf[512], option[64], arg[512];
475 if (!path || !*path || (f = fopen (path, "r")) == NULL)
476 return FALSE;
478 while (fgets (buf, sizeof (buf), f))
480 sscanf (buf, "%63s %511[^\n]", option, arg);
481 s = option; /* Strip trailing ':' or '=' */
482 while (*s && *s != ':' && *s != '=')
483 ++s;
484 *s = '\0';
485 s = arg; /* Strip leading ':', '=', and whitespace */
486 while (*s == ' ' || *s == '\t' || *s == ':' || *s == '=')
487 ++s;
489 for (list = config_color_list; list; list = list->next)
491 cc = (ConfigColor *) list->data;
492 ha = cc->attributes;
493 if (!strcmp (option, ha->name))
495 *(char **) ha->value = g_strdup (s);
496 cc->color_is_mapped = FALSE;
497 ghid_set_special_colors (ha);
498 break;
502 fclose (f);
504 ghid_layer_buttons_color_update ();
505 return TRUE;
508 static gchar *
509 expand_dir (gchar * dir)
511 gchar *s;
513 if (*dir == '~')
514 s = g_build_filename ((gchar *) g_get_home_dir (), dir + 1, NULL);
515 else
516 s = g_strdup (dir);
517 return s;
520 static void
521 add_to_paths_list (GList ** list, gchar * path_string)
523 gchar *p, *paths;
525 paths = g_strdup (path_string);
526 for (p = strtok (paths, PCB_PATH_DELIMETER); p && *p; p = strtok (NULL, PCB_PATH_DELIMETER))
527 *list = g_list_prepend (*list, expand_dir (p));
528 g_free (paths);
531 /* Parse command line code borrowed from hid/common/hidinit.c
533 static void
534 parse_optionv (gint * argc, gchar *** argv, gboolean from_cmd_line)
536 HID_AttrNode *ha;
537 HID_Attribute *a;
538 gchar *ep;
539 gint e, ok, offset;
540 gboolean matched = FALSE;
542 offset = from_cmd_line ? 2 : 0;
544 while (*argc
545 && (((*argv)[0][0] == '-' && (*argv)[0][1] == '-')
546 || !from_cmd_line))
548 for (ha = hid_attr_nodes; ha; ha = ha->next)
550 for (a = ha->attributes; a < ha->attributes + ha->n; ++a)
552 if (!a->name || strcmp ((*argv)[0] + offset, a->name))
553 continue;
554 switch (a->type)
556 case HID_Label:
557 break;
558 case HID_Integer:
559 if (a->value)
560 *(int *) a->value = strtol ((*argv)[1], 0, 0);
561 else
562 a->default_val.int_value = strtol ((*argv)[1], 0, 0);
563 (*argc)--;
564 (*argv)++;
565 break;
566 case HID_Real:
567 if (a->value)
568 *(double *) a->value = strtod ((*argv)[1], 0);
569 else
570 a->default_val.real_value = strtod ((*argv)[1], 0);
571 (*argc)--;
572 (*argv)++;
573 break;
574 case HID_String:
575 if (a->value)
576 *(char **) a->value = g_strdup((*argv)[1]);
577 else
578 a->default_val.str_value = g_strdup((*argv)[1]);
579 (*argc)--;
580 (*argv)++;
581 break;
582 case HID_Boolean:
583 if (a->value)
584 *(char *) a->value = 1;
585 else
586 a->default_val.int_value = 1;
587 break;
588 case HID_Mixed:
589 abort ();
590 a->default_val.real_value = strtod ((*argv)[1], &ep);
591 goto do_enum;
592 case HID_Enum:
593 ep = (*argv)[1];
594 do_enum:
595 ok = 0;
596 for (e = 0; a->enumerations[e]; e++)
597 if (strcmp (a->enumerations[e], (*argv)[1]) == 0)
599 ok = 1;
600 a->default_val.int_value = e;
601 a->default_val.str_value = ep;
602 break;
604 if (!ok)
606 fprintf (stderr,
607 "ERROR: \"%s\" is an unknown value for the --%s option\n",
608 (*argv)[1], a->name);
609 exit (1);
611 (*argc)--;
612 (*argv)++;
613 break;
614 case HID_Path:
615 abort ();
616 a->default_val.str_value = (*argv)[1];
617 (*argc)--;
618 (*argv)++;
619 break;
621 (*argc)--;
622 (*argv)++;
623 ha = 0;
624 goto got_match;
626 if (a < ha->attributes + ha->n)
627 matched = TRUE;
629 if (!matched)
631 if (from_cmd_line)
633 fprintf (stderr, "unrecognized option: %s\n", (*argv)[0]);
634 exit (1);
636 else
637 // ghid_log("unrecognized option: %s\n", (*argv)[0]);
638 fprintf (stderr, "unrecognized option: %s\n", (*argv)[0]);
640 got_match:;
642 (*argc)++;
643 (*argv)--;
646 static void
647 load_rc_file (gchar * path)
649 FILE *f;
650 gchar buf[1024], *av[2], **argv;
651 gint argc;
653 f = fopen (path, "r");
654 if (!f)
655 return;
657 if (Settings.verbose)
658 printf ("Loading pcbrc file: %s\n", path);
659 while (fgets (buf, sizeof (buf), f))
661 argv = &(av[0]);
662 if ((argc = parse_option_line (buf, &av[0], &av[1])) > 0)
663 parse_optionv (&argc, &argv, FALSE);
664 g_free (av[0]);
665 g_free (av[1]);
667 fclose (f);
670 static void
671 load_rc_files (void)
673 gchar *path;
675 load_rc_file ("/etc/pcbrc");
676 load_rc_file ("/usr/local/etc/pcbrc");
678 path = g_build_filename (pcblibdir, "pcbrc", NULL);
679 load_rc_file (path);
680 g_free (path);
682 path = g_build_filename ((gchar *) g_get_home_dir (), ".pcb/pcbrc", NULL);
683 load_rc_file (path);
684 g_free (path);
686 load_rc_file ("pcbrc");
690 void
691 ghid_config_files_read (gint * argc, gchar *** argv)
693 GList *list;
694 gchar *str, *dir;
695 gint width, height;
697 ghidgui = &_ghidgui;
699 ghid_config_init ();
700 load_rc_files ();
701 config_file_read ();
702 config_colors_read (color_file);
703 (*argc)--;
704 (*argv)++;
705 parse_optionv (argc, argv, TRUE);
707 if (board_size_override
708 && sscanf (board_size_override, "%dx%d", &width, &height) == 2)
710 Settings.MaxWidth = TO_PCB_UNITS (width);
711 Settings.MaxHeight = TO_PCB_UNITS (height);
714 if (lib_newlib_config && *lib_newlib_config)
715 add_to_paths_list (&lib_newlib_list, lib_newlib_config);
717 for (list = lib_newlib_list; list; list = list->next)
719 str = Settings.LibraryTree;
720 dir = expand_dir ((gchar *) list->data);
721 Settings.LibraryTree = g_strconcat (str, PCB_PATH_DELIMETER, dir, NULL);
722 g_free (dir);
723 g_free (str);
727 void
728 ghid_config_files_write (void)
730 FILE *f;
731 ConfigAttribute *ca;
733 if (!ghidgui->config_modified || (f = config_file_open ("w")) == NULL)
734 return;
736 fprintf (f, "### PCB configuration file. ###\n");
738 for (ca = &config_attributes[0];
739 ca < &config_attributes[0] + G_N_ELEMENTS (config_attributes); ++ca)
741 switch (ca->type)
743 case CONFIG_Boolean:
744 fprintf (f, "%s = %d\n", ca->name, (gint) * (gchar *) ca->value);
745 break;
747 case CONFIG_Integer:
748 fprintf (f, "%s = %d\n", ca->name, *(gint *) ca->value);
749 break;
751 case CONFIG_Real:
752 fprintf (f, "%s = %f\n", ca->name, *(double *) ca->value);
753 break;
755 case CONFIG_String:
756 if (*(char **) ca->value == NULL)
757 fprintf (f, "# %s = NULL\n", ca->name);
758 else
759 fprintf (f, "%s = %s\n", ca->name, *(char **) ca->value);
760 break;
761 default:
762 break;
765 fclose (f);
767 ghidgui->config_modified = FALSE;
770 /* =================== OK, now the gui stuff ======================
772 static GtkWidget *config_window;
774 /* -------------- The General config page ----------------
777 static void
778 config_command_window_toggle_cb (GtkToggleButton * button, gpointer data)
780 gboolean active = gtk_toggle_button_get_active (button);
781 static gboolean holdoff;
783 if (holdoff)
784 return;
786 /* Can't toggle into command window mode if the status line command
787 | entry is active.
789 if (ghidgui->command_entry_status_line_active)
791 holdoff = TRUE;
792 gtk_toggle_button_set_active (button, FALSE);
793 holdoff = FALSE;
794 return;
796 ghidgui->use_command_window = active;
797 ghid_command_use_command_window_sync ();
801 static void
802 config_compact_horizontal_toggle_cb (GtkToggleButton * button, gpointer data)
804 gboolean active = gtk_toggle_button_get_active (button);
806 ghidgui->compact_horizontal = active;
807 if (active)
809 gtk_container_remove (GTK_CONTAINER (ghidgui->compact_hbox),
810 ghidgui->position_hbox);
811 gtk_box_pack_end (GTK_BOX (ghidgui->compact_vbox),
812 ghidgui->position_hbox, TRUE, FALSE, 0);
814 else
816 gtk_container_remove (GTK_CONTAINER (ghidgui->compact_vbox),
817 ghidgui->position_hbox);
818 gtk_box_pack_end(GTK_BOX(ghidgui->compact_hbox), ghidgui->position_hbox,
819 FALSE, FALSE, 4);
821 ghid_set_status_line_label ();
822 ghidgui->config_modified = TRUE;
825 static void
826 config_compact_vertical_toggle_cb (GtkToggleButton * button, gpointer data)
828 gboolean active = gtk_toggle_button_get_active (button);
830 ghidgui->compact_vertical = active;
831 ghid_pack_mode_buttons();
832 ghidgui->config_modified = TRUE;
835 static void
836 config_title_window_cb (GtkToggleButton * button, gpointer data)
838 gboolean active = gtk_toggle_button_get_active (button);
840 ghidgui->ghid_title_window = active;
841 ghid_window_set_name_label (ghidgui->name_label_string);
842 ghidgui->config_modified = TRUE;
845 static void
846 config_general_toggle_cb (GtkToggleButton * button, gint * setting)
848 *setting = gtk_toggle_button_get_active (button);
849 ghidgui->config_modified = TRUE;
852 static void
853 config_backup_spin_button_cb (GtkSpinButton * spin_button, gpointer data)
855 Settings.BackupInterval = gtk_spin_button_get_value_as_int (spin_button);
856 EnableAutosave ();
857 ghidgui->config_modified = TRUE;
860 static void
861 config_history_spin_button_cb (GtkSpinButton * spin_button, gpointer data)
863 ghidgui->history_size = gtk_spin_button_get_value_as_int (spin_button);
864 ghidgui->config_modified = TRUE;
867 static void
868 config_auto_pan_speed_spin_button_cb (GtkSpinButton * spin_button,
869 gpointer data)
871 ghidgui->auto_pan_speed = gtk_spin_button_get_value_as_int (spin_button);
872 ghidgui->config_modified = TRUE;
875 static void
876 config_general_tab_create (GtkWidget * tab_vbox)
878 GtkWidget *vbox;
880 gtk_container_set_border_width (GTK_CONTAINER (tab_vbox), 6);
882 vbox = ghid_category_vbox (tab_vbox, _("Enables"), 4, 2, TRUE, TRUE);
884 ghid_check_button_connected (vbox, NULL, ghidgui->use_command_window,
885 TRUE, FALSE, FALSE, 2,
886 config_command_window_toggle_cb, NULL,
887 _("Use separate window for command entry"));
889 ghid_check_button_connected (vbox, NULL, ghidgui->compact_horizontal,
890 TRUE, FALSE, FALSE, 2,
891 config_compact_horizontal_toggle_cb, NULL,
892 _("Alternate window layout to allow smaller horizontal size"));
894 ghid_check_button_connected (vbox, NULL, ghidgui->compact_vertical,
895 TRUE, FALSE, FALSE, 2,
896 config_compact_vertical_toggle_cb, NULL,
897 _("Alternate window layout to allow smaller vertical size"));
899 ghid_check_button_connected (vbox, NULL, ghidgui->ghid_title_window,
900 TRUE, FALSE, FALSE, 2,
901 config_title_window_cb, NULL,
902 _("Put layout name on the window title bar"));
904 vbox = ghid_category_vbox (tab_vbox, _("Backups"), 4, 2, TRUE, TRUE);
905 ghid_check_button_connected (vbox, NULL, Settings.SaveInTMP,
906 TRUE, FALSE, FALSE, 2,
907 config_general_toggle_cb, &Settings.SaveInTMP,
908 _("If layout is modified at exit, save into PCB.%i.save"));
909 ghid_spin_button (vbox, NULL, Settings.BackupInterval, 0.0, 60 * 60, 60.0,
910 600.0, 0, 0, config_backup_spin_button_cb, NULL, FALSE,
911 _("Seconds between auto backups\n"
912 "(set to zero to disable auto backups)"));
914 vbox = ghid_category_vbox (tab_vbox, _("Misc"), 4, 2, TRUE, TRUE);
915 ghid_spin_button (vbox, NULL, ghidgui->history_size,
916 5.0, 25.0, 1.0, 1.0, 0, 0,
917 config_history_spin_button_cb, NULL, FALSE,
918 _("Number of commands to remember in the history list"));
919 ghid_spin_button (vbox, NULL, ghidgui->auto_pan_speed,
920 1.0, 10.0, 1.0, 1.0, 0, 0,
921 config_auto_pan_speed_spin_button_cb, NULL, FALSE,
922 _("Auto pan speed"));
926 static void
927 config_general_apply (void)
929 /* save the settings */
930 ghid_config_files_write ();
934 /* -------------- The Sizes config page ----------------
936 #define STEP0_SMALL_SIZE (Settings.grid_units_mm ? 0.005 : 0.1)
937 #define STEP1_SMALL_SIZE (Settings.grid_units_mm ? 0.05 : 1.0)
938 #define STEP0_SIZE (Settings.grid_units_mm ? 5.0 : 100)
939 #define STEP1_SIZE (Settings.grid_units_mm ? 25.0 : 1000)
940 #define SPIN_DIGITS (Settings.grid_units_mm ? 3 : 1)
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;
948 static gint new_board_width, new_board_height;
950 static void
951 config_sizes_apply (void)
953 gboolean active;
955 active =
956 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
957 (use_board_size_default_button));
958 if (active)
960 Settings.MaxWidth = new_board_width;
961 Settings.MaxHeight = new_board_height;
962 ghidgui->config_modified = TRUE;
965 active =
966 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
967 (use_drc_sizes_default_button));
968 if (active)
970 Settings.Bloat = PCB->Bloat;
971 Settings.Shrink = PCB->Shrink;
972 Settings.minWid = PCB->minWid;
973 Settings.minSlk = PCB->minSlk;
974 Settings.IsleArea = PCB->IsleArea;
975 Settings.minDrill = PCB->minDrill;
976 Settings.minRing = PCB->minRing;
977 ghidgui->config_modified = TRUE;
980 if (PCB->MaxWidth != new_board_width || PCB->MaxHeight != new_board_height)
981 ChangePCBSize (new_board_width, new_board_height);
984 static void
985 text_spin_button_cb (GtkSpinButton * spin, gint * dst)
987 *dst = gtk_spin_button_get_value_as_int (spin);
988 ghidgui->config_modified = TRUE;
989 ghid_set_status_line_label ();
993 static void
994 size_spin_button_cb (GtkSpinButton * spin, gint * dst)
996 gdouble value;
998 value = gtk_spin_button_get_value (spin);
999 *dst = TO_PCB_UNITS (value);
1000 ghidgui->config_modified = TRUE;
1003 static void
1004 config_sizes_tab_create (GtkWidget * tab_vbox)
1006 GtkWidget *table, *vbox, *hbox, *label;
1007 gchar *str;
1009 /* Need a vbox we can destroy if user changes grid units.
1011 if (!config_sizes_vbox)
1013 vbox = gtk_vbox_new (FALSE, 0);
1014 gtk_box_pack_start (GTK_BOX (tab_vbox), vbox, FALSE, FALSE, 0);
1015 gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
1016 config_sizes_vbox = vbox;
1017 config_sizes_tab_vbox = tab_vbox;
1020 str = g_strdup_printf (_("<b>%s</b> grid units are selected"),
1021 Settings.grid_units_mm ? "mm" : "mil");
1022 label = gtk_label_new ("");
1023 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
1024 gtk_label_set_markup (GTK_LABEL (label), str);
1025 g_free (str);
1027 gtk_box_pack_start (GTK_BOX (config_sizes_vbox), label, FALSE, FALSE, 4);
1030 /* ---- Board Size ---- */
1031 vbox = ghid_category_vbox (config_sizes_vbox, _("Board Size"),
1032 4, 2, TRUE, TRUE);
1033 hbox = gtk_hbox_new (FALSE, 0);
1034 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1035 table = gtk_table_new (2, 2, FALSE);
1036 gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
1037 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1038 gtk_table_set_row_spacings (GTK_TABLE (table), 3);
1040 new_board_width = PCB->MaxWidth;
1041 new_board_height = PCB->MaxHeight;
1042 ghid_table_spin_button (table, 0, 0, NULL,
1043 FROM_PCB_UNITS (PCB->MaxWidth),
1044 FROM_PCB_UNITS (MIN_SIZE),
1045 FROM_PCB_UNITS (MAX_COORD), STEP0_SIZE, STEP1_SIZE,
1046 SPIN_DIGITS, 0, size_spin_button_cb,
1047 &new_board_width, FALSE, _("Width"));
1049 ghid_table_spin_button (table, 1, 0, NULL,
1050 FROM_PCB_UNITS (PCB->MaxHeight),
1051 FROM_PCB_UNITS (MIN_SIZE),
1052 FROM_PCB_UNITS (MAX_COORD), STEP0_SIZE, STEP1_SIZE,
1053 SPIN_DIGITS, 0, size_spin_button_cb,
1054 &new_board_height, FALSE, _("Height"));
1055 ghid_check_button_connected (vbox, &use_board_size_default_button, FALSE,
1056 TRUE, FALSE, FALSE, 0, NULL, NULL,
1058 ("Use this board size as the default for new layouts"));
1060 /* ---- Text Scale ---- */
1061 vbox = ghid_category_vbox (config_sizes_vbox, _("Text Scale"),
1062 4, 2, TRUE, TRUE);
1063 hbox = gtk_hbox_new (FALSE, 0);
1064 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1065 table = gtk_table_new (4, 2, FALSE);
1066 gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
1067 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1068 gtk_table_set_row_spacings (GTK_TABLE (table), 3);
1070 ghid_table_spin_button (table, 0, 0, &config_text_spin_button,
1071 Settings.TextScale,
1072 MIN_TEXTSCALE, MAX_TEXTSCALE,
1073 10.0, 10.0,
1074 0, 0, text_spin_button_cb,
1075 &Settings.TextScale, FALSE, "%");
1078 /* ---- DRC Sizes ---- */
1079 vbox = ghid_category_vbox (config_sizes_vbox, _("Design Rule Checking"),
1080 4, 2, TRUE, TRUE);
1081 hbox = gtk_hbox_new (FALSE, 0);
1082 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1083 table = gtk_table_new (4, 2, FALSE);
1084 gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
1085 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1086 gtk_table_set_row_spacings (GTK_TABLE (table), 3);
1088 ghid_table_spin_button (table, 0, 0, NULL,
1089 FROM_PCB_UNITS (PCB->Bloat),
1090 FROM_PCB_UNITS (MIN_DRC_VALUE),
1091 FROM_PCB_UNITS (MAX_DRC_VALUE), STEP0_SMALL_SIZE,
1092 STEP1_SMALL_SIZE, SPIN_DIGITS, 0,
1093 size_spin_button_cb, &PCB->Bloat, FALSE,
1094 _("Minimum copper spacing"));
1096 ghid_table_spin_button (table, 1, 0, NULL,
1097 FROM_PCB_UNITS (PCB->minWid),
1098 FROM_PCB_UNITS (MIN_DRC_VALUE),
1099 FROM_PCB_UNITS (MAX_DRC_VALUE), STEP0_SMALL_SIZE,
1100 STEP1_SMALL_SIZE, SPIN_DIGITS, 0,
1101 size_spin_button_cb, &PCB->minWid, FALSE,
1102 _("Minimum copper width"));
1104 ghid_table_spin_button (table, 2, 0, NULL,
1105 FROM_PCB_UNITS (PCB->Shrink),
1106 FROM_PCB_UNITS (MIN_DRC_VALUE),
1107 FROM_PCB_UNITS (MAX_DRC_VALUE), STEP0_SMALL_SIZE,
1108 STEP1_SMALL_SIZE, SPIN_DIGITS, 0,
1109 size_spin_button_cb, &PCB->Shrink, FALSE,
1110 _("Minimum touching copper overlap"));
1112 ghid_table_spin_button (table, 3, 0, NULL,
1113 FROM_PCB_UNITS (PCB->minSlk),
1114 FROM_PCB_UNITS (MIN_DRC_SILK),
1115 FROM_PCB_UNITS (MAX_DRC_SILK), STEP0_SMALL_SIZE,
1116 STEP1_SMALL_SIZE, SPIN_DIGITS, 0,
1117 size_spin_button_cb, &PCB->minSlk, FALSE,
1118 _("Minimum silk width"));
1120 ghid_table_spin_button (table, 4, 0, NULL,
1121 FROM_PCB_UNITS (PCB->minDrill),
1122 FROM_PCB_UNITS (MIN_DRC_DRILL),
1123 FROM_PCB_UNITS (MAX_DRC_DRILL), STEP0_SMALL_SIZE,
1124 STEP1_SMALL_SIZE, SPIN_DIGITS, 0,
1125 size_spin_button_cb, &PCB->minDrill, FALSE,
1126 _("Minimum drill diameter"));
1128 ghid_table_spin_button (table, 5, 0, NULL,
1129 FROM_PCB_UNITS (PCB->minRing),
1130 FROM_PCB_UNITS (MIN_DRC_RING),
1131 FROM_PCB_UNITS (MAX_DRC_RING), STEP0_SMALL_SIZE,
1132 STEP1_SMALL_SIZE, SPIN_DIGITS, 0,
1133 size_spin_button_cb, &PCB->minRing, FALSE,
1134 _("Minimum annular ring"));
1136 ghid_check_button_connected (vbox, &use_drc_sizes_default_button, FALSE,
1137 TRUE, FALSE, FALSE, 0, NULL, NULL,
1139 ("Use DRC values as the default for new layouts"));
1141 gtk_widget_show_all (config_sizes_vbox);
1145 /* -------------- The Increments config page ----------------
1147 /* Increment/decrement values are kept in mil and mm units and not in
1148 | PCB units.
1150 static GtkWidget *config_increments_vbox, *config_increments_tab_vbox;
1152 static void
1153 increment_spin_button_cb (GtkSpinButton * spin, gdouble * dst)
1155 gdouble value;
1157 value = gtk_spin_button_get_value (spin);
1158 *dst = value; /* Not using PCB units */
1161 ghidgui->config_modified = TRUE;
1164 static void
1165 config_increments_tab_create (GtkWidget * tab_vbox)
1167 GtkWidget *vbox, *label;
1168 gdouble *target;
1169 gchar *str;
1171 /* Need a vbox we can destroy if user changes grid units.
1173 if (!config_increments_vbox)
1175 vbox = gtk_vbox_new (FALSE, 0);
1176 gtk_box_pack_start (GTK_BOX (tab_vbox), vbox, FALSE, FALSE, 0);
1177 gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
1178 config_increments_vbox = vbox;
1179 config_increments_tab_vbox = tab_vbox;
1182 str =
1183 g_strdup_printf (_
1184 ("Increment/Decrement values to use in <b>%s</b> units mode.\n"),
1185 Settings.grid_units_mm ? "mm" : "mil");
1186 label = gtk_label_new ("");
1187 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
1188 gtk_label_set_markup (GTK_LABEL (label), str);
1189 gtk_box_pack_start (GTK_BOX (config_increments_vbox), label,
1190 FALSE, FALSE, 4);
1191 g_free (str);
1194 /* ---- Grid Increment/Decrement ---- */
1195 vbox = ghid_category_vbox (config_increments_vbox,
1196 _("Grid Increment/Decrement"), 4, 2, TRUE, TRUE);
1198 /* Grid increment spin button ('g' and '<shift>g'). For mil
1199 | units, range from 1.0 to 25.0. For mm, range from 0.01 to 1.0
1200 | Step sizes of 5 mil or .05 mm, and .01 mm precision or 1 mil precision.
1202 target = Settings.grid_units_mm ?
1203 &Settings.grid_increment_mm : &Settings.grid_increment_mil;
1204 ghid_spin_button (vbox, NULL,
1205 GRID_UNITS_VALUE (Settings.grid_increment_mm,
1206 Settings.grid_increment_mil),
1207 GRID_UNITS_VALUE (0.01, 1.0), GRID_UNITS_VALUE (1.0,
1208 25.0),
1209 GRID_UNITS_VALUE (0.05, 5.0), GRID_UNITS_VALUE (0.05,
1210 5.0),
1211 GRID_UNITS_VALUE (2, 0), 0, increment_spin_button_cb,
1212 target, FALSE,
1213 _("For 'g' and '<shift>g' grid change actions"));
1216 /* ---- Size Increment/Decrement ---- */
1217 vbox = ghid_category_vbox (config_increments_vbox,
1218 _("Size Increment/Decrement"), 4, 2, TRUE, TRUE);
1220 /* Size increment spin button ('s' and '<shift>s'). For mil
1221 | units, range from 1.0 to 10.0. For mm, range from 0.01 to 0.5
1222 | Step sizes of 1 mil or .01 mm, and .01 mm precision or 1 mil precision.
1224 target = Settings.grid_units_mm ?
1225 &Settings.size_increment_mm : &Settings.size_increment_mil;
1226 ghid_spin_button (vbox, NULL,
1227 GRID_UNITS_VALUE (Settings.size_increment_mm,
1228 Settings.size_increment_mil),
1229 GRID_UNITS_VALUE (0.01, 1.0), GRID_UNITS_VALUE (0.5,
1230 10.0),
1231 GRID_UNITS_VALUE (0.01, 1.0), GRID_UNITS_VALUE (0.05,
1232 5.0),
1233 GRID_UNITS_VALUE (2, 0), 0, increment_spin_button_cb,
1234 target, FALSE,
1235 _("For 's' and '<shift>s' size change actions on lines,\n"
1236 "pads, pins and text.\n"
1237 "Use '<ctrl>s' and '<shift><ctrl>s' for drill holes."));
1239 /* ---- Line Increment/Decrement ---- */
1240 vbox = ghid_category_vbox (config_increments_vbox,
1241 _("Line Increment/Decrement"), 4, 2, TRUE, TRUE);
1243 /* Line increment spin button ('l' and '<shift>l'). For mil
1244 | units, range from 0.5 to 10.0. For mm, range from 0.005 to 0.5
1245 | Step sizes of 0.5 mil or .005 mm, and .001 mm precision or 0.1 mil
1246 | precision.
1248 target = Settings.grid_units_mm ?
1249 &Settings.line_increment_mm : &Settings.line_increment_mil;
1250 ghid_spin_button (vbox, NULL,
1251 GRID_UNITS_VALUE (Settings.line_increment_mm,
1252 Settings.line_increment_mil),
1253 GRID_UNITS_VALUE (0.005, 0.5), GRID_UNITS_VALUE (0.5,
1254 10.0),
1255 GRID_UNITS_VALUE (0.005, 0.5), GRID_UNITS_VALUE (0.05,
1256 5.0),
1257 GRID_UNITS_VALUE (3, 1), 0, increment_spin_button_cb,
1258 target, FALSE,
1260 ("For 'l' and '<shift>l' routing line width change actions"));
1262 /* ---- Clear Increment/Decrement ---- */
1263 vbox = ghid_category_vbox (config_increments_vbox,
1264 _("Clear Increment/Decrement"), 4, 2, TRUE,
1265 TRUE);
1267 /* Clear increment spin button ('l' and '<shift>l'). For mil
1268 | units, range from 0.5 to 10.0. For mm, range from 0.005 to 0.5
1269 | Step sizes of 0.5 mil or .005 mm, and .001 mm precision or 0.1 mil
1270 | precision.
1272 target = Settings.grid_units_mm ?
1273 &Settings.clear_increment_mm : &Settings.clear_increment_mil;
1274 ghid_spin_button (vbox, NULL,
1275 GRID_UNITS_VALUE (Settings.clear_increment_mm,
1276 Settings.clear_increment_mil),
1277 GRID_UNITS_VALUE (0.005, 0.5), GRID_UNITS_VALUE (0.5,
1278 10.0),
1279 GRID_UNITS_VALUE (0.005, 0.5), GRID_UNITS_VALUE (0.05,
1280 5.0),
1281 GRID_UNITS_VALUE (3, 1), 0, increment_spin_button_cb,
1282 target, FALSE,
1284 ("For 'k' and '<shift>k' line clearance inside polygon size\n"
1285 "change actions"));
1288 gtk_widget_show_all (config_increments_vbox);
1291 /* -------------- The Library config page ----------------
1293 static GtkWidget *library_newlib_entry;
1295 static void
1296 config_library_apply (void)
1298 if (dup_string
1299 (&lib_newlib_config, ghid_entry_get_text (library_newlib_entry)))
1300 ghidgui->config_modified = TRUE;
1303 static void
1304 config_library_tab_create (GtkWidget * tab_vbox)
1306 GtkWidget *vbox, *label, *entry;
1308 gtk_container_set_border_width (GTK_CONTAINER (tab_vbox), 6);
1309 vbox = ghid_category_vbox (tab_vbox, _("Element Directories"),
1310 4, 2, TRUE, TRUE);
1311 label = gtk_label_new ("");
1312 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
1313 gtk_label_set_markup (GTK_LABEL (label),
1315 ("<small>Enter a \""
1316 PCB_PATH_DELIMETER
1317 "\" separated list of custom top level\n"
1318 "element directories. For example:\n"
1319 "\t<b>~/gaf/pcb-elements"
1320 PCB_PATH_DELIMETER
1321 "packages"
1322 PCB_PATH_DELIMETER
1323 "/usr/local/pcb-elements</b>\n"
1324 "Elements should be organized into subdirectories below each\n"
1325 "top level directory. Restart program for changes to take effect."
1326 "</small>"));
1328 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
1329 entry = gtk_entry_new ();
1330 library_newlib_entry = entry;
1331 gtk_entry_set_text (GTK_ENTRY (entry), lib_newlib_config);
1332 gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 4);
1336 /* -------------- The Layers Group config page ----------------
1338 static GtkWidget *config_groups_table, *config_groups_vbox, *config_groups_window;
1340 static GtkWidget *layer_entry[MAX_LAYER];
1341 static GtkWidget *group_button[MAX_LAYER + 2][MAX_LAYER];
1343 #if FIXME
1344 static GtkWidget *use_layer_default_button;
1345 #endif
1347 static gint config_layer_group[MAX_LAYER + 2];
1349 static LayerGroupType layer_groups, /* Working copy */
1350 *lg_monitor; /* Keep track if our working copy */
1351 /* needs to be changed (new layout) */
1353 static gboolean groups_modified, groups_holdoff, layers_applying;
1355 static gchar *layer_info_text[] = {
1356 N_("<h>Layer Names\n"),
1357 N_("You may enter layer names for the layers drawn on the screen.\n"
1358 "The special 'component side' and 'solder side' are layers which\n"
1359 "will be printed out, so they must have in their group at least one\n"
1360 "of the other layers that are drawn on the screen.\n"),
1361 "\n",
1362 N_("<h>Layer Groups\n"),
1363 N_("Each layer on the screen may be in its own group which allows the\n"
1364 "maximum number of board layers. However, for boards with fewer\n"
1365 "layers, you may group layers together which will then print as a\n"
1366 "single layer on a printout. This allows a visual color distinction\n"
1367 "to be displayed on the screen for signal groups which will print as\n"
1368 "a single layer\n"),
1369 "\n",
1370 N_("For example, for a 4 layer board a useful layer group arrangement\n"
1371 "can be to have 3 screen displayed layers grouped into the same group\n"
1372 "as the 'component side' and 'solder side' printout layers. Then\n"
1373 "groups such as signals, ground, and supply traces can be color\n"
1374 "coded on the screen while printing as a single layer. For this\n"
1375 "you would select buttons and enter names on the Setup page to\n"
1376 "structure four layer groups similar to this:\n"),
1377 "\n",
1378 N_("<b>Group 1:"),
1379 "\n\t",
1380 N_("solder"),
1381 "\n\t",
1382 N_("GND-solder"),
1383 "\n\t",
1384 N_("Vcc-solder"),
1385 "\n\t",
1386 N_("solder side"),
1387 "\n",
1388 N_("<b>Group 2:"),
1389 "\n\t",
1390 N_("component"),
1391 "\n\t",
1392 N_("GND-component"),
1393 "\n\t",
1394 N_("Vcc-component"),
1395 "\n\t",
1396 N_("component side"),
1397 "\n",
1398 N_("<b>Group 3:"),
1399 "\n\t",
1400 N_("signal1"),
1401 "\n",
1402 N_("<b>Group 4:"),
1403 "\n\t",
1404 N_("signal2"),
1405 "\n"
1408 static void
1409 config_layer_groups_radio_button_cb (GtkToggleButton * button, gpointer data)
1411 gint layer = GPOINTER_TO_INT (data) >> 8;
1412 gint group = GPOINTER_TO_INT (data) & 0xff;
1414 if (!gtk_toggle_button_get_active (button) || groups_holdoff)
1415 return;
1416 config_layer_group[layer] = group;
1417 groups_modified = TRUE;
1418 ghidgui->config_modified = TRUE;
1421 /* Construct a layer group string. Follow logic in WritePCBDataHeader(),
1422 | but use g_string functions.
1424 static gchar *
1425 make_layer_group_string (LayerGroupType * lg)
1427 GString *string;
1428 gint group, entry, layer;
1430 string = g_string_new ("");
1432 for (group = 0; group < max_layer; group++)
1434 if (lg->Number[group] == 0)
1435 continue;
1436 for (entry = 0; entry < lg->Number[group]; entry++)
1438 layer = lg->Entries[group][entry];
1439 if (layer == max_layer + COMPONENT_LAYER)
1440 string = g_string_append (string, "c");
1441 else if (layer == max_layer + SOLDER_LAYER)
1442 string = g_string_append (string, "s");
1443 else
1444 g_string_append_printf (string, "%d", layer + 1);
1446 if (entry != lg->Number[group] - 1)
1447 string = g_string_append (string, ",");
1449 if (group != max_layer - 1)
1450 string = g_string_append (string, ":");
1452 return g_string_free (string, FALSE); /* Don't free string->str */
1455 static void
1456 config_layers_apply (void)
1458 LayerType *layer;
1459 gchar *s;
1460 gint group, i;
1461 gint componentgroup = 0, soldergroup = 0;
1462 gboolean use_as_default = FALSE, layers_modified = FALSE;
1464 #if FIXME
1465 use_as_default =
1466 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
1467 (use_layer_default_button));
1468 #endif
1470 /* Get each layer name entry and dup if modified into the PCB layer names
1471 | and, if to use as default, the Settings layer names.
1473 for (i = 0; i < max_layer; ++i)
1475 layer = &PCB->Data->Layer[i];
1476 s = ghid_entry_get_text (layer_entry[i]);
1477 if (dup_string (&layer->Name, s))
1478 layers_modified = TRUE;
1479 /* FIXME */
1480 if (use_as_default && dup_string (&Settings.DefaultLayerName[i], s))
1481 ghidgui->config_modified = TRUE;
1484 /* Layer names can be changed from the menus and that can update the
1485 | config. So holdoff the loop.
1487 layers_applying = TRUE;
1488 if (layers_modified)
1489 ghid_layer_buttons_update ();
1490 layers_applying = FALSE;
1492 if (groups_modified) /* If any group radio buttons were toggled. */
1494 /* clear all entries and read layer by layer
1496 for (group = 0; group < max_layer; group++)
1497 layer_groups.Number[group] = 0;
1499 for (i = 0; i < max_layer + 2; i++)
1501 group = config_layer_group[i] - 1;
1502 layer_groups.Entries[group][layer_groups.Number[group]++] = i;
1504 if (i == max_layer + COMPONENT_LAYER)
1505 componentgroup = group;
1506 else if (i == max_layer + SOLDER_LAYER)
1507 soldergroup = group;
1510 /* do some cross-checking
1511 | solder-side and component-side must be in different groups
1512 | solder-side and component-side must not be the only one in the group
1514 if (layer_groups.Number[soldergroup] <= 1
1515 || layer_groups.Number[componentgroup] <= 1)
1517 Message (_
1518 ("Both 'solder side' or 'component side' layers must have at least\n"
1519 "\tone other layer in their group.\n"));
1520 return;
1522 else if (soldergroup == componentgroup)
1524 Message (_
1525 ("The 'solder side' and 'component side' layers are not allowed\n"
1526 "\tto be in the same layer group #\n"));
1527 return;
1529 PCB->LayerGroups = layer_groups;
1530 ghid_invalidate_all();
1531 groups_modified = FALSE;
1533 if (use_as_default)
1535 s = make_layer_group_string (&PCB->LayerGroups);
1536 if (dup_string (&Settings.Groups, s))
1538 ParseGroupString (Settings.Groups, &Settings.LayerGroups, max_layer);
1539 ghidgui->config_modified = TRUE;
1541 g_free (s);
1545 static void
1546 config_layer_group_button_state_update (void)
1548 gint g, i;
1550 /* Set button active corresponding to layer group state.
1552 groups_holdoff = TRUE;
1553 for (g = 0; g < max_layer; g++)
1554 for (i = 0; i < layer_groups.Number[g]; i++)
1556 /* printf("layer %d in group %d\n", layer_groups.Entries[g][i], g +1); */
1557 config_layer_group[layer_groups.Entries[g][i]] = g + 1;
1558 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
1559 (group_button
1560 [layer_groups.Entries[g][i]][g]),
1561 TRUE);
1563 groups_holdoff = FALSE;
1566 static void
1567 layer_name_entry_cb(GtkWidget *entry, gpointer data)
1569 gint i = GPOINTER_TO_INT(data);
1570 LayerType *layer;
1571 gchar *name;
1573 layer = &PCB->Data->Layer[i];
1574 name = ghid_entry_get_text(entry);
1575 if (dup_string (&layer->Name, name))
1576 ghid_layer_buttons_update();
1579 void
1580 ghid_config_groups_changed(void)
1582 GtkWidget *vbox, *table, *button, *label, *scrolled_window;
1583 GSList *group;
1584 gchar buf[32], *name;
1585 gint layer, i;
1587 if (!config_groups_vbox)
1588 return;
1589 vbox = config_groups_vbox;
1591 if (config_groups_table)
1592 gtk_widget_destroy(config_groups_table);
1593 if (config_groups_window)
1594 gtk_widget_destroy(config_groups_window);
1596 config_groups_window = scrolled_window =
1597 gtk_scrolled_window_new (NULL, NULL);
1598 gtk_widget_set_size_request (scrolled_window, 34, 408);
1599 gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 3);
1600 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
1601 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1602 gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
1603 gtk_widget_show (scrolled_window);
1606 table = gtk_table_new (max_layer + 3, max_layer + 1, FALSE);
1607 config_groups_table = table;
1608 gtk_table_set_row_spacings (GTK_TABLE (table), 3);
1609 gtk_scrolled_window_add_with_viewport (
1610 GTK_SCROLLED_WINDOW (scrolled_window), table);
1611 gtk_widget_show (table);
1613 layer_groups = PCB->LayerGroups; /* working copy */
1614 lg_monitor = &PCB->LayerGroups; /* So can know if PCB changes on us */
1616 label = gtk_label_new (_("Group #"));
1617 gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1);
1618 gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
1620 for (i = 1; i < max_layer + 1; ++i)
1622 if (i < 10)
1623 snprintf (buf, sizeof (buf), " %d", i);
1624 else
1625 snprintf (buf, sizeof (buf), "%d", i);
1626 label = gtk_label_new (buf);
1627 gtk_table_attach_defaults (GTK_TABLE (table), label, i, i + 1, 0, 1);
1630 /* Create a row of radio toggle buttons for layer. So each layer
1631 | can have an active radio button set for the group it needs to be in.
1633 for (layer = 0; layer < max_layer + 2; ++layer)
1635 if (layer == max_layer + COMPONENT_LAYER)
1636 name = _("component side");
1637 else if (layer == max_layer + SOLDER_LAYER)
1638 name = _("solder side");
1639 else
1640 name = UNKNOWN (PCB->Data->Layer[layer].Name);
1642 if (layer >= max_layer)
1644 label = gtk_label_new (name);
1645 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1646 gtk_table_attach_defaults (GTK_TABLE (table), label,
1647 0, 1, layer + 1, layer + 2);
1649 else
1651 layer_entry[layer] = gtk_entry_new ();
1652 gtk_entry_set_text (GTK_ENTRY (layer_entry[layer]), name);
1653 gtk_table_attach_defaults (GTK_TABLE (table), layer_entry[layer],
1654 0, 1, layer + 1, layer + 2);
1655 g_signal_connect(G_OBJECT(layer_entry[layer]), "activate",
1656 G_CALLBACK(layer_name_entry_cb), GINT_TO_POINTER(layer));
1659 group = NULL;
1660 for (i = 0; i < max_layer; ++i)
1662 snprintf (buf, sizeof (buf), "%2.2d", i+1);
1663 button = gtk_radio_button_new_with_label (group, buf);
1665 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE);
1666 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
1667 gtk_table_attach_defaults (GTK_TABLE (table), button,
1668 i + 1, i + 2, layer + 1, layer + 2);
1669 g_signal_connect (G_OBJECT (button), "toggled",
1670 G_CALLBACK (config_layer_groups_radio_button_cb),
1671 GINT_TO_POINTER ((layer << 8) | (i + 1)));
1672 group_button[layer][i] = button;
1675 gtk_widget_show_all(config_groups_vbox);
1676 config_layer_group_button_state_update ();
1680 static void
1681 edit_layer_button_cb(GtkWidget *widget, gchar *data)
1683 gchar **argv;
1685 if (PCB->RatDraw || PCB->SilkActive)
1686 return;
1688 argv = g_strsplit(data, ",", -1);
1689 MoveLayerAction(2, argv, 0, 0);
1690 g_strfreev(argv);
1693 static void
1694 config_layers_tab_create (GtkWidget * tab_vbox)
1696 GtkWidget *tabs, *vbox, *vbox1, *button, *text, *sep;
1697 GtkWidget *hbox, *arrow;
1698 gint i;
1700 tabs = gtk_notebook_new ();
1701 gtk_box_pack_start (GTK_BOX (tab_vbox), tabs, TRUE, TRUE, 0);
1703 /* -- Change tab */
1704 vbox = ghid_notebook_page(tabs, _("Change"), 0, 6);
1705 vbox1 = ghid_category_vbox(vbox,
1706 _("Operations on currently selected layer:"),
1707 4, 2, TRUE, TRUE);
1709 button = gtk_button_new();
1710 arrow = gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_ETCHED_IN);
1711 gtk_container_add(GTK_CONTAINER(button), arrow);
1712 g_signal_connect(G_OBJECT(button), "clicked",
1713 G_CALLBACK(edit_layer_button_cb), "c,up");
1714 hbox = gtk_hbox_new(FALSE, 0);
1715 gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
1716 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1718 button = gtk_button_new();
1719 arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_ETCHED_IN);
1720 gtk_container_add(GTK_CONTAINER(button), arrow);
1721 g_signal_connect(G_OBJECT(button), "clicked",
1722 G_CALLBACK(edit_layer_button_cb), "c,down");
1723 hbox = gtk_hbox_new(FALSE, 0);
1724 gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
1725 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1727 button = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1728 g_signal_connect(G_OBJECT(button), "clicked",
1729 G_CALLBACK(edit_layer_button_cb), "c,-1");
1730 hbox = gtk_hbox_new(FALSE, 0);
1731 gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
1732 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1734 vbox1 = ghid_category_vbox(vbox,
1735 _("Add new layer above currently selected layer:"),
1736 4, 2, TRUE, TRUE);
1737 button = gtk_button_new_from_stock(GTK_STOCK_ADD);
1738 g_signal_connect(G_OBJECT(button), "clicked",
1739 G_CALLBACK(edit_layer_button_cb), "-1,c");
1740 hbox = gtk_hbox_new(FALSE, 0);
1741 gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
1742 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1744 /* -- Groups tab */
1745 vbox = ghid_notebook_page (tabs, _("Groups"), 0, 6);
1746 config_groups_vbox = gtk_vbox_new(FALSE, 0);
1747 gtk_box_pack_start(GTK_BOX(vbox), config_groups_vbox, FALSE, FALSE, 0);
1748 ghid_config_groups_changed();
1750 sep = gtk_hseparator_new ();
1751 gtk_box_pack_start (GTK_BOX (vbox), sep, FALSE, FALSE, 4);
1753 #if FIXME
1754 ghid_check_button_connected (vbox, &use_layer_default_button, FALSE,
1755 TRUE, FALSE, FALSE, 8, NULL, NULL,
1756 ("Use these layer settings as the default for new layouts"));
1757 #endif
1760 /* -- Info tab */
1761 vbox = ghid_notebook_page (tabs, _("Info"), 0, 6);
1763 text = ghid_scrolled_text_view (vbox, NULL,
1764 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1765 for (i = 0; i < sizeof (layer_info_text) / sizeof (gchar *); ++i)
1766 ghid_text_view_append (text, _(layer_info_text[i]));
1770 void
1771 ghid_config_layer_name_update (gchar * name, gint layer)
1773 if (!config_window || layers_applying || !name)
1774 return;
1775 gtk_entry_set_text (GTK_ENTRY (layer_entry[layer]), name);
1777 /* If we get a config layer name change because a new PCB is loaded
1778 | or new layout started, need to change our working layer group copy.
1780 if (lg_monitor != &PCB->LayerGroups)
1782 layer_groups = PCB->LayerGroups;
1783 lg_monitor = &PCB->LayerGroups;
1784 config_layer_group_button_state_update ();
1785 groups_modified = FALSE;
1789 /* -------------- The Colors config page ----------------
1791 static GtkWidget *config_colors_vbox,
1792 *config_colors_tab_vbox,
1793 *config_colors_save_button,
1794 *config_color_file_label, *config_color_warn_label;
1796 static void config_colors_tab_create (GtkWidget * tab_vbox);
1798 static gboolean config_colors_modified;
1800 static void
1801 config_color_file_set_label (void)
1803 gchar *str, *name;
1805 if (!*color_file)
1806 name = g_strdup ("defaults");
1807 else
1808 name = g_path_get_basename (color_file);
1810 str = g_strdup_printf ("Current colors loaded: <b>%s</b>", name);
1811 gtk_label_set_markup (GTK_LABEL (config_color_file_label), str);
1812 g_free (name);
1813 g_free (str);
1816 static void
1817 config_color_defaults_cb (gpointer data)
1819 GList *list;
1820 ConfigColor *cc;
1821 HID_Attribute *ha;
1823 for (list = config_color_list; list; list = list->next)
1825 cc = (ConfigColor *) list->data;
1826 ha = cc->attributes;
1827 dup_string ((char **) ha->value, ha->default_val.str_value);
1828 cc->color_is_mapped = FALSE;
1829 ghid_set_special_colors (ha);
1832 dup_string (&color_file, "");
1833 ghidgui->config_modified = TRUE;
1835 gtk_widget_set_sensitive (config_colors_save_button, FALSE);
1836 gtk_widget_set_sensitive (config_color_warn_label, FALSE);
1837 config_color_file_set_label ();
1838 config_colors_modified = FALSE;
1840 ghid_layer_buttons_color_update ();
1842 /* Receate the colors config page to pick up new colors.
1844 gtk_widget_destroy (config_colors_vbox);
1845 config_colors_tab_create (config_colors_tab_vbox);
1847 ghid_invalidate_all();
1850 static void
1851 config_color_load_cb (gpointer data)
1853 gchar *path, *dir = g_strdup (color_dir);
1855 path = ghid_dialog_file_select_open (_("Load Color File"), &dir, NULL);
1856 if (path)
1858 config_colors_read (path);
1859 dup_string (&color_file, path);
1860 ghidgui->config_modified = TRUE;
1862 gtk_widget_set_sensitive (config_colors_save_button, FALSE);
1863 gtk_widget_set_sensitive (config_color_warn_label, FALSE);
1864 config_color_file_set_label ();
1865 config_colors_modified = FALSE;
1867 g_free (path);
1868 g_free (dir);
1870 /* Receate the colors config page to pick up new colors.
1872 gtk_widget_destroy (config_colors_vbox);
1873 config_colors_tab_create (config_colors_tab_vbox);
1875 ghid_invalidate_all();
1878 static void
1879 config_color_save_cb (gpointer data)
1881 gchar *name, *path, *dir = g_strdup (color_dir);
1883 path =
1884 ghid_dialog_file_select_save (_("Save Color File"), &dir, NULL, NULL);
1885 if (path)
1887 name = g_path_get_basename (path);
1888 if (!strcmp (name, "default"))
1889 ghid_dialog_message (_
1890 ("Sorry, not overwriting the default color file!"));
1891 else
1893 config_colors_write (path);
1894 dup_string (&color_file, path);
1895 ghidgui->config_modified = TRUE;
1897 gtk_widget_set_sensitive (config_colors_save_button, FALSE);
1898 gtk_widget_set_sensitive (config_color_warn_label, FALSE);
1899 config_color_file_set_label ();
1900 config_colors_modified = FALSE;
1902 g_free (name);
1904 g_free (path);
1905 g_free (dir);
1908 static void
1909 config_color_set_cb (GtkWidget * button, ConfigColor * cc)
1911 GdkColor new_color;
1912 HID_Attribute *ha = cc->attributes;
1913 gchar *str;
1915 gtk_color_button_get_color (GTK_COLOR_BUTTON (button), &new_color);
1916 str = ghid_get_color_name (&new_color);
1917 ghid_map_color_string (str, &cc->color);
1918 *(char **) ha->value = str;
1919 /* g_free(str); Memory leak */
1921 config_colors_modified = TRUE;
1922 gtk_widget_set_sensitive (config_colors_save_button, TRUE);
1923 gtk_widget_set_sensitive (config_color_warn_label, TRUE);
1925 ghid_layer_buttons_color_update ();
1926 ghid_invalidate_all();
1929 static void
1930 config_color_button_create (GtkWidget * box, ConfigColor * cc)
1932 GtkWidget *button, *hbox, *label;
1933 HID_Attribute *ha = cc->attributes;
1934 gchar *title;
1936 hbox = gtk_hbox_new (FALSE, 6);
1937 gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 0);
1939 if (!cc->color_is_mapped)
1940 ghid_map_color_string (*(char **) ha->value, &cc->color);
1941 cc->color_is_mapped = TRUE;
1943 title = g_strdup_printf (_("PCB %s Color"), ha->name);
1944 button = gtk_color_button_new_with_color (&cc->color);
1945 gtk_color_button_set_title (GTK_COLOR_BUTTON (button), title);
1946 g_free (title);
1948 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1949 label = gtk_label_new (ha->name);
1950 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1951 g_signal_connect (G_OBJECT (button), "color-set",
1952 G_CALLBACK (config_color_set_cb), cc);
1955 static void
1956 config_colors_tab_create (GtkWidget * tab_vbox)
1958 GtkWidget *scrolled_vbox, *vbox, *hbox, *expander, *sep;
1959 GList *list;
1960 ConfigColor *cc;
1962 vbox = gtk_vbox_new (FALSE, 0);
1963 gtk_box_pack_start (GTK_BOX (tab_vbox), vbox, TRUE, TRUE, 0);
1964 gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
1966 config_colors_vbox = vbox; /* can be destroyed if color file loaded */
1967 config_colors_tab_vbox = tab_vbox;
1969 scrolled_vbox = ghid_scrolled_vbox (config_colors_vbox, NULL,
1970 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1972 /* ---- Main colors ---- */
1973 expander = gtk_expander_new (_("Main colors"));
1974 gtk_box_pack_start (GTK_BOX (scrolled_vbox), expander, FALSE, FALSE, 2);
1975 vbox = gtk_vbox_new (FALSE, 0);
1976 gtk_container_add (GTK_CONTAINER (expander), vbox);
1977 vbox = ghid_category_vbox (vbox, NULL, 0, 2, TRUE, FALSE);
1979 for (list = config_color_list; list; list = list->next)
1981 cc = (ConfigColor *) list->data;
1982 if (cc->type != MISC_COLOR)
1983 continue;
1984 config_color_button_create (vbox, cc);
1987 /* ---- Layer colors ---- */
1988 expander = gtk_expander_new (_("Layer colors"));
1989 gtk_box_pack_start (GTK_BOX (scrolled_vbox), expander, FALSE, FALSE, 2);
1990 vbox = gtk_vbox_new (FALSE, 0);
1991 gtk_container_add (GTK_CONTAINER (expander), vbox);
1992 vbox = ghid_category_vbox (vbox, NULL, 0, 2, TRUE, FALSE);
1994 for (list = config_color_list; list; list = list->next)
1996 cc = (ConfigColor *) list->data;
1997 if (cc->type != LAYER_COLOR)
1998 continue;
1999 config_color_button_create (vbox, cc);
2002 /* ---- Selected colors ---- */
2003 expander = gtk_expander_new (_("Selected colors"));
2004 gtk_box_pack_start (GTK_BOX (scrolled_vbox), expander, FALSE, FALSE, 2);
2005 vbox = gtk_vbox_new (FALSE, 0);
2006 gtk_container_add (GTK_CONTAINER (expander), vbox);
2007 vbox = ghid_category_vbox (vbox, NULL, 0, 2, TRUE, FALSE);
2009 for (list = config_color_list; list; list = list->next)
2011 cc = (ConfigColor *) list->data;
2012 if (cc->type != MISC_SELECTED_COLOR)
2013 continue;
2014 config_color_button_create (vbox, cc);
2016 sep = gtk_hseparator_new ();
2017 gtk_box_pack_start (GTK_BOX (vbox), sep, FALSE, FALSE, 2);
2018 for (list = config_color_list; list; list = list->next)
2020 cc = (ConfigColor *) list->data;
2021 if (cc->type != LAYER_SELECTED_COLOR)
2022 continue;
2023 config_color_button_create (vbox, cc);
2026 config_color_warn_label = gtk_label_new ("");
2027 gtk_label_set_use_markup (GTK_LABEL (config_color_warn_label), TRUE);
2028 gtk_label_set_markup (GTK_LABEL (config_color_warn_label),
2029 _("<b>Warning:</b> unsaved color changes will be lost"
2030 " at program exit."));
2031 gtk_box_pack_start (GTK_BOX (config_colors_vbox), config_color_warn_label,
2032 FALSE, FALSE, 4);
2034 hbox = gtk_hbox_new (FALSE, 0);
2035 gtk_box_pack_start (GTK_BOX (config_colors_vbox), hbox, FALSE, FALSE, 6);
2037 config_color_file_label = gtk_label_new ("");
2038 gtk_label_set_use_markup (GTK_LABEL (config_color_file_label), TRUE);
2039 config_color_file_set_label ();
2040 gtk_box_pack_start (GTK_BOX (hbox), config_color_file_label,
2041 FALSE, FALSE, 0);
2043 ghid_button_connected (hbox, NULL, FALSE, FALSE, FALSE, 4,
2044 config_color_load_cb, NULL, _("Load"));
2045 ghid_button_connected (hbox, &config_colors_save_button,
2046 FALSE, FALSE, FALSE, 4,
2047 config_color_save_cb, NULL, _("Save"));
2048 ghid_button_connected (hbox, NULL, FALSE, FALSE, FALSE, 4,
2049 config_color_defaults_cb, NULL, _("Defaults"));
2051 gtk_widget_set_sensitive (config_colors_save_button,
2052 config_colors_modified);
2053 gtk_widget_set_sensitive (config_color_warn_label, config_colors_modified);
2054 gtk_widget_show_all (config_colors_vbox);
2058 /* --------------- The main config page -----------------
2060 enum
2062 CONFIG_NAME_COLUMN,
2063 CONFIG_PAGE_COLUMN,
2064 N_CONFIG_COLUMNS
2067 static GtkNotebook *config_notebook;
2069 static GtkWidget *
2070 config_page_create (GtkTreeStore * tree, GtkTreeIter * iter,
2071 GtkNotebook * notebook)
2073 GtkWidget *vbox;
2074 gint page;
2076 vbox = gtk_vbox_new (FALSE, 0);
2077 gtk_notebook_append_page (notebook, vbox, NULL);
2078 page = g_list_length (notebook->children) - 1;
2079 gtk_tree_store_set (tree, iter, CONFIG_PAGE_COLUMN, page, -1);
2080 return vbox;
2083 void
2084 ghid_config_handle_units_changed (void)
2086 ghid_set_cursor_position_labels ();
2087 gtk_label_set_markup (GTK_LABEL (ghidgui->grid_units_label),
2088 Settings.grid_units_mm ?
2089 "<b>mm</b> " : "<b>mil</b> ");
2090 if (config_sizes_vbox)
2092 gtk_widget_destroy (config_sizes_vbox);
2093 config_sizes_vbox = NULL;
2094 config_sizes_tab_create (config_sizes_tab_vbox);
2096 if (config_increments_vbox)
2098 gtk_widget_destroy (config_increments_vbox);
2099 config_increments_vbox = NULL;
2100 config_increments_tab_create (config_increments_tab_vbox);
2102 ghidgui->config_modified = TRUE;
2105 void
2106 ghid_config_text_scale_update (void)
2108 if (config_window)
2109 gtk_spin_button_set_value (GTK_SPIN_BUTTON (config_text_spin_button),
2110 (gdouble) Settings.TextScale);
2113 static void
2114 config_close_cb (gpointer data)
2116 /* Config pages may need to check for modified entries, use as default
2117 | options, etc when the config window is closed.
2119 config_sizes_apply ();
2120 config_layers_apply ();
2121 config_library_apply ();
2122 config_general_apply ();
2124 config_sizes_vbox = NULL;
2125 config_increments_vbox = NULL;
2127 config_groups_vbox = config_groups_table = NULL;
2128 config_groups_window = NULL;
2130 gtk_widget_destroy (config_window);
2131 config_window = NULL;
2134 static void
2135 config_destroy_cb (gpointer data)
2137 config_sizes_vbox = NULL;
2138 config_increments_vbox = NULL;
2139 config_groups_vbox = config_groups_table = NULL;
2140 config_groups_window = NULL;
2141 gtk_widget_destroy (config_window);
2142 config_window = NULL;
2145 static void
2146 config_selection_changed_cb (GtkTreeSelection * selection, gpointer data)
2148 GtkTreeIter iter;
2149 GtkTreeModel *model;
2150 gint page;
2152 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
2153 return;
2154 gtk_tree_model_get (model, &iter, CONFIG_PAGE_COLUMN, &page, -1);
2155 gtk_notebook_set_current_page (config_notebook, page);
2158 void
2159 ghid_config_window_show (void)
2161 GtkWidget *widget, *main_vbox, *vbox, *config_hbox, *hbox;
2162 GtkWidget *scrolled;
2163 GtkWidget *button;
2164 GtkTreeStore *model;
2165 GtkTreeView *treeview;
2166 GtkTreeIter iter;
2167 GtkCellRenderer *renderer;
2168 GtkTreeViewColumn *column;
2169 GtkTreeSelection *select;
2171 if (config_window)
2173 gtk_window_present (GTK_WINDOW (config_window));
2174 return;
2177 config_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2178 g_signal_connect (G_OBJECT (config_window), "delete_event",
2179 G_CALLBACK (config_destroy_cb), NULL);
2181 gtk_window_set_title (GTK_WINDOW (config_window), "PCB Preferences");
2182 gtk_window_set_wmclass (GTK_WINDOW (config_window), "Pcb_Conf", "PCB");
2183 gtk_container_set_border_width (GTK_CONTAINER (config_window), 2);
2185 config_hbox = gtk_hbox_new (FALSE, 4);
2186 gtk_container_add (GTK_CONTAINER (config_window), config_hbox);
2188 scrolled = gtk_scrolled_window_new (NULL, NULL);
2189 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
2190 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
2191 gtk_box_pack_start (GTK_BOX (config_hbox), scrolled, FALSE, FALSE, 0);
2193 main_vbox = gtk_vbox_new (FALSE, 4);
2194 gtk_box_pack_start (GTK_BOX (config_hbox), main_vbox, TRUE, TRUE, 0);
2196 widget = gtk_notebook_new ();
2197 gtk_box_pack_start (GTK_BOX (main_vbox), widget, TRUE, TRUE, 0);
2198 config_notebook = GTK_NOTEBOOK (widget);
2199 gtk_notebook_set_show_tabs (config_notebook, FALSE);
2201 model = gtk_tree_store_new (N_CONFIG_COLUMNS, G_TYPE_STRING, G_TYPE_INT);
2204 /* -- General -- */
2205 gtk_tree_store_append (model, &iter, NULL);
2206 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("General"), -1);
2207 vbox = config_page_create (model, &iter, config_notebook);
2208 config_general_tab_create (vbox);
2211 /* -- Sizes -- */
2212 gtk_tree_store_append (model, &iter, NULL);
2213 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("Sizes"), -1);
2214 vbox = config_page_create (model, &iter, config_notebook);
2215 config_sizes_tab_create (vbox);
2217 /* -- Increments -- */
2218 gtk_tree_store_append (model, &iter, NULL);
2219 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("Increments"), -1);
2220 vbox = config_page_create (model, &iter, config_notebook);
2221 config_increments_tab_create (vbox);
2223 /* -- Library -- */
2224 gtk_tree_store_append (model, &iter, NULL);
2225 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("Library"), -1);
2226 vbox = config_page_create (model, &iter, config_notebook);
2227 config_library_tab_create (vbox);
2229 /* -- Layer names and groups -- */
2230 gtk_tree_store_append (model, &iter, NULL);
2231 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("Layers"), -1);
2232 vbox = config_page_create (model, &iter, config_notebook);
2233 config_layers_tab_create (vbox);
2236 /* -- Colors -- */
2237 gtk_tree_store_append (model, &iter, NULL);
2238 gtk_tree_store_set (model, &iter, CONFIG_NAME_COLUMN, _("Colors"), -1);
2239 vbox = config_page_create (model, &iter, config_notebook);
2240 config_colors_tab_create (vbox);
2243 /* Create the tree view
2245 treeview =
2246 GTK_TREE_VIEW (gtk_tree_view_new_with_model (GTK_TREE_MODEL (model)));
2247 g_object_unref (G_OBJECT (model)); /* Don't need the model anymore */
2249 renderer = gtk_cell_renderer_text_new ();
2250 column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
2251 "text",
2252 CONFIG_NAME_COLUMN,
2253 NULL);
2254 gtk_tree_view_append_column (treeview, column);
2255 gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (treeview));
2258 select = gtk_tree_view_get_selection (treeview);
2259 gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
2260 g_signal_connect (G_OBJECT (select), "changed",
2261 G_CALLBACK (config_selection_changed_cb), NULL);
2264 hbox = gtk_hbutton_box_new ();
2265 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
2266 gtk_box_set_spacing (GTK_BOX (hbox), 5);
2267 gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
2269 button = gtk_button_new_from_stock (GTK_STOCK_OK);
2270 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
2271 g_signal_connect (G_OBJECT (button), "clicked",
2272 G_CALLBACK (config_close_cb), NULL);
2273 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
2274 gtk_widget_grab_default (button);
2276 gtk_widget_show_all (config_window);