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.
37 #include "../hidint.h"
46 #include "misc.h" /* MKDIR() */
47 #include "pcb-printf.h"
53 #ifdef HAVE_LIBDMALLOC
57 extern int MoveLayerAction(int argc
, char **argv
, int x
, int y
);
88 HID_Attribute
*attributes
;
91 gboolean color_is_mapped
;
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
},
177 dup_core_string (gchar
** dst
, const gchar
* src
)
179 if (dst
== NULL
|| (*dst
== NULL
&& src
== NULL
))
182 if (*dst
!= NULL
&& src
!= NULL
&& strcmp (*dst
, src
) == 0)
186 *dst
= (src
== NULL
) ? NULL
: strdup (src
);
192 config_file_open (gchar
* mode
)
195 gchar
*homedir
, *fname
;
198 homedir
= (gchar
*) g_get_home_dir ();
201 g_message ("config_file_open: Can't get home directory!");
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!",
220 if (!color_dir
) /* Convenient to make the color dir here */
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!",
233 fname
= g_build_path (G_DIR_SEPARATOR_S
,
234 color_dir
, "Default", NULL
);
235 dup_string (&color_file
, fname
);
240 fname
= g_build_path (G_DIR_SEPARATOR_S
, config_dir
, PCB_CONFIG_FILE
, NULL
);
241 f
= fopen (fname
, mode
);
247 static ConfigAttribute
*
248 lookup_config_attribute (gchar
* name
, gboolean if_null_value
)
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
)
266 ghid_config_init (void)
270 ConfigAttribute
*ca
, dummy_attribute
;
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
)
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
;
292 *(char *) a
->value
= a
->default_val
.int_value
;
293 ca
->type
= CONFIG_Boolean
;
296 *(int *) a
->value
= a
->default_val
.int_value
;
297 ca
->type
= CONFIG_Integer
;
300 *(Coord
*) a
->value
= a
->default_val
.coord_value
;
301 ca
->type
= CONFIG_Coord
;
304 *(double *) a
->value
= a
->default_val
.real_value
;
305 ca
->type
= CONFIG_Real
;
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
)
318 cc
= g_new0 (ConfigColor
, 1);
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
;
328 cc
->type
= MISC_COLOR
;
330 config_color_list
= g_list_append (config_color_list
, cc
);
335 *(int *) a
->value
= a
->default_val
.int_value
;
350 parse_option_line (gchar
* line
, gchar
** option_result
, gchar
** arg_result
)
352 gchar
*s
, *ss
, option
[64], arg
[512];
356 *option_result
= NULL
;
361 while (*s
== ' ' || *s
== '\t')
363 if (!*s
|| *s
== '\n' || *s
== '#' || *s
== '[')
365 if ((ss
= strchr (s
, '\n')) != NULL
)
368 sscanf (s
, "%63s %511[^\n]", option
, arg
);
370 s
= option
; /* Strip trailing ':' or '=' */
371 while (*s
&& *s
!= ':' && *s
!= '=')
375 s
= arg
; /* Strip leading ':', '=', and whitespace */
376 while (*s
== ' ' || *s
== '\t' || *s
== ':' || *s
== '=' || *s
== '"')
378 if ((ss
= strchr (s
, '"')) != NULL
)
382 *option_result
= g_strdup (option
);
383 if (arg_result
&& *s
)
385 *arg_result
= g_strdup (s
);
392 set_config_attribute (gchar
* option
, gchar
* arg
)
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.
404 locale_point
= *lc
->decimal_point
;
407 if ((ca
= lookup_config_attribute (option
, FALSE
)) == NULL
)
412 *(gchar
*) ca
->value
= (gchar
) atoi (arg
);
416 *(gint
*) ca
->value
= atoi (arg
);
420 /* Hopefully temporary locale decimal point check:
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
;
430 *(double *) ca
->value
= atof (arg
);
434 dup_string ((gchar
**) ca
->value
, arg
? arg
: (gchar
*)"");
437 *(Coord
*) ca
->value
= GetValue (arg
, NULL
, NULL
);
446 config_file_read (void)
449 gchar buf
[512], *option
, *arg
;
451 if ((f
= config_file_open ("r")) == NULL
)
455 while (fgets (buf
, sizeof (buf
), f
))
457 if (parse_option_line (buf
, &option
, &arg
) > 0)
458 set_config_attribute (option
, arg
);
467 config_colors_write (gchar
* path
)
474 if ((f
= fopen (path
, "w")) == NULL
)
476 for (list
= config_color_list
; list
; list
= list
->next
)
478 cc
= (ConfigColor
*) list
->data
;
480 fprintf (f
, "%s =\t%s\n", ha
->name
, *(char **) ha
->value
);
486 config_colors_read (gchar
* path
)
492 gchar
*s
, buf
[512], option
[64], arg
[512];
494 if (!path
|| !*path
|| (f
= fopen (path
, "r")) == NULL
)
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
!= '=')
504 s
= arg
; /* Strip leading ':', '=', and whitespace */
505 while (*s
== ' ' || *s
== '\t' || *s
== ':' || *s
== '=')
508 for (list
= config_color_list
; list
; list
= list
->next
)
510 cc
= (ConfigColor
*) list
->data
;
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
);
527 expand_dir (gchar
* dir
)
532 s
= g_build_filename ((gchar
*) g_get_home_dir (), dir
+ 1, NULL
);
539 add_to_paths_list (GList
** list
, gchar
* path_string
)
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
));
549 /* Parse command line code borrowed from hid/common/hidinit.c
552 parse_optionv (gint
* argc
, gchar
*** argv
, gboolean from_cmd_line
)
559 gboolean matched
= FALSE
;
561 offset
= from_cmd_line
? 2 : 0;
564 && (((*argv
)[0][0] == '-' && (*argv
)[0][1] == '-')
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
))
579 *(int *) a
->value
= strtol ((*argv
)[1], 0, 0);
581 a
->default_val
.int_value
= strtol ((*argv
)[1], 0, 0);
587 *(Coord
*) a
->value
= GetValue ((*argv
)[1], 0, 0);
589 a
->default_val
.coord_value
= GetValue ((*argv
)[1], 0, 0);
595 *(double *) a
->value
= strtod ((*argv
)[1], 0);
597 a
->default_val
.real_value
= strtod ((*argv
)[1], 0);
603 *(char **) a
->value
= g_strdup((*argv
)[1]);
605 a
->default_val
.str_value
= g_strdup((*argv
)[1]);
611 *(char *) a
->value
= 1;
613 a
->default_val
.int_value
= 1;
616 a
->default_val
.real_value
= strtod ((*argv
)[1], &ep
);
622 for (e
= 0; a
->enumerations
[e
]; e
++)
623 if (strcmp (a
->enumerations
[e
], ep
) == 0)
626 a
->default_val
.int_value
= e
;
627 a
->default_val
.str_value
= ep
;
633 "ERROR: \"%s\" is an unknown value for the --%s option\n",
634 (*argv
)[1], a
->name
);
642 a
->default_val
.str_value
= (*argv
)[1];
647 unit
= get_unit_struct ((*argv
)[1]);
651 "ERROR: unit \"%s\" is unknown to pcb (option --%s)\n",
652 (*argv
)[1], a
->name
);
655 a
->default_val
.int_value
= unit
->index
;
656 a
->default_val
.str_value
= unit
->suffix
;
666 if (a
< ha
->attributes
+ ha
->n
)
673 fprintf (stderr
, "unrecognized option: %s\n", (*argv
)[0]);
677 // ghid_log("unrecognized option: %s\n", (*argv)[0]);
678 fprintf (stderr
, "unrecognized option: %s\n", (*argv
)[0]);
687 load_rc_file (gchar
* path
)
690 gchar buf
[1024], *av
[2], **argv
;
693 f
= fopen (path
, "r");
697 if (Settings
.verbose
)
698 printf ("Loading pcbrc file: %s\n", path
);
699 while (fgets (buf
, sizeof (buf
), f
))
702 if ((argc
= parse_option_line (buf
, &av
[0], &av
[1])) > 0)
703 parse_optionv (&argc
, &argv
, FALSE
);
715 load_rc_file ("/etc/pcbrc");
716 load_rc_file ("/usr/local/etc/pcbrc");
718 path
= g_build_filename (pcblibdir
, "pcbrc", NULL
);
722 path
= g_build_filename ((gchar
*) g_get_home_dir (), ".pcb/pcbrc", NULL
);
726 load_rc_file ("pcbrc");
731 ghid_config_files_read (gint
* argc
, gchar
*** argv
)
742 config_colors_read (color_file
);
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
);
768 ghid_config_files_write (void)
773 if (!ghidgui
->config_modified
|| (f
= config_file_open ("w")) == NULL
)
776 fprintf (f
, "### PCB configuration file. ###\n");
778 for (ca
= &config_attributes
[0];
779 ca
< &config_attributes
[0] + G_N_ELEMENTS (config_attributes
); ++ca
)
784 fprintf (f
, "%s = %d\n", ca
->name
, (gint
) * (gchar
*) ca
->value
);
788 fprintf (f
, "%s = %d\n", ca
->name
, *(gint
*) ca
->value
);
792 fprintf (f
, "%s = %f\n", ca
->name
, *(double *) ca
->value
);
796 if (*(char **) ca
->value
== NULL
)
797 fprintf (f
, "# %s = NULL\n", ca
->name
);
799 fprintf (f
, "%s = %s\n", ca
->name
, *(char **) ca
->value
);
807 ghidgui
->config_modified
= FALSE
;
810 /* =================== OK, now the gui stuff ======================
812 static GtkWidget
*config_window
;
814 /* -------------- The General config page ----------------
818 config_command_window_toggle_cb (GtkToggleButton
* button
, gpointer data
)
820 gboolean active
= gtk_toggle_button_get_active (button
);
821 static gboolean holdoff
;
826 /* Can't toggle into command window mode if the status line command
829 if (ghidgui
->command_entry_status_line_active
)
832 gtk_toggle_button_set_active (button
, FALSE
);
836 ghidgui
->use_command_window
= active
;
837 ghid_command_use_command_window_sync ();
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
;
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
;
862 config_general_toggle_cb (GtkToggleButton
* button
, void * setting
)
864 *(gint
*)setting
= gtk_toggle_button_get_active (button
);
865 ghidgui
->config_modified
= TRUE
;
869 config_backup_spin_button_cb (GtkSpinButton
* spin_button
, gpointer data
)
871 Settings
.BackupInterval
= gtk_spin_button_get_value_as_int (spin_button
);
873 ghidgui
->config_modified
= TRUE
;
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
;
884 config_general_tab_create (GtkWidget
* tab_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"));
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
;
945 config_sizes_apply (void)
950 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
951 (use_board_size_default_button
));
954 Settings
.MaxWidth
= new_board_width
;
955 Settings
.MaxHeight
= new_board_height
;
956 ghidgui
->config_modified
= TRUE
;
960 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
961 (use_drc_sizes_default_button
));
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
);
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 ();
987 coord_entry_cb (GHidCoordEntry
* ce
, void * dst
)
989 *(Coord
*) dst
= ghid_coord_entry_get_value (ce
);
990 ghidgui
->config_modified
= TRUE
;
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"),
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"),
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
,
1046 MIN_TEXTSCALE
, MAX_TEXTSCALE
,
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"),
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
,
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
1112 static GtkWidget
*config_increments_vbox
, *config_increments_tab_vbox
;
1115 increment_spin_button_cb (GHidCoordEntry
* ce
, void * dst
)
1117 *(Coord
*)dst
= ghid_coord_entry_get_value (ce
);
1118 ghidgui
->config_modified
= TRUE
;
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, \
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"
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"
1195 gtk_widget_show_all (config_increments_vbox
);
1198 /* -------------- The Library config page ----------------
1200 static GtkWidget
*library_newlib_entry
;
1203 config_library_apply (void)
1206 (&lib_newlib_config
, ghid_entry_get_text (library_newlib_entry
)))
1207 ghidgui
->config_modified
= TRUE
;
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"),
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 \""
1224 "\" separated list of custom top level\n"
1225 "element directories. For example:\n"
1226 "\t<b>~/gaf/pcb-elements"
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."
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
];
1251 static GtkWidget
*use_layer_default_button
;
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"),
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"),
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"),
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
)
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.
1332 make_layer_group_string (LayerGroupType
* lg
)
1335 gint group
, entry
, layer
;
1337 string
= g_string_new ("");
1339 for (group
= 0; group
< max_group
; group
++)
1341 if (lg
->Number
[group
] == 0)
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");
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 */
1363 config_layers_apply (void)
1368 gint componentgroup
= 0, soldergroup
= 0;
1369 gboolean use_as_default
= FALSE
, layers_modified
= FALSE
;
1373 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
1374 (use_layer_default_button
));
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
;
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)
1425 ("Both, 'top side' and 'bottom side' layer must have at least\n"
1426 "\tone other layer in their group.\n"));
1429 else if (soldergroup
== componentgroup
)
1432 ("The 'top side' and 'bottom side' layers are not allowed\n"
1433 "\tto be in the same layer group #\n"));
1436 PCB
->LayerGroups
= layer_groups
;
1437 ghid_invalidate_all();
1438 groups_modified
= FALSE
;
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
;
1453 config_layer_group_button_state_update (void)
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
1467 [layer_groups
.Entries
[g
][i
]][g
]),
1470 groups_holdoff
= FALSE
;
1474 layer_name_entry_cb(GtkWidget
*entry
, gpointer data
)
1476 gint i
= GPOINTER_TO_INT(data
);
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();
1487 ghid_config_groups_changed(void)
1489 GtkWidget
*vbox
, *table
, *button
, *label
, *scrolled_window
;
1491 gchar buf
[32], *name
;
1494 if (!config_groups_vbox
)
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
)
1530 snprintf (buf
, sizeof (buf
), " %d", i
);
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");
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);
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
));
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 ();
1588 edit_layer_button_cb(GtkWidget
*widget
, gchar
*data
)
1592 if (PCB
->RatDraw
|| PCB
->SilkActive
)
1595 argv
= g_strsplit(data
, ",", -1);
1596 MoveLayerAction(2, argv
, 0, 0);
1601 config_layers_tab_create (GtkWidget
* tab_vbox
)
1603 GtkWidget
*tabs
, *vbox
, *vbox1
, *button
, *text
, *sep
;
1604 GtkWidget
*hbox
, *arrow
;
1607 tabs
= gtk_notebook_new ();
1608 gtk_box_pack_start (GTK_BOX (tab_vbox
), tabs
, TRUE
, TRUE
, 0);
1611 vbox
= ghid_notebook_page(tabs
, _("Change"), 0, 6);
1612 vbox1
= ghid_category_vbox(vbox
,
1613 _("Operations on currently selected layer:"),
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:"),
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);
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);
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"));
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
]));
1678 ghid_config_layer_name_update (gchar
* name
, gint layer
)
1680 if (!config_window
|| layers_applying
|| !name
)
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
;
1708 config_color_file_set_label (void)
1713 name
= g_strdup ("defaults");
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
);
1724 config_color_defaults_cb (gpointer data
)
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();
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
);
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
;
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();
1787 config_color_save_cb (gpointer data
)
1789 gchar
*name
, *path
, *dir
= g_strdup (color_dir
);
1792 ghid_dialog_file_select_save (_("Save Color File"), &dir
, NULL
, NULL
);
1795 name
= g_path_get_basename (path
);
1796 if (!strcmp (name
, "default"))
1797 ghid_dialog_message (_
1798 ("Sorry, not overwriting the default color file!"));
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
;
1817 config_color_set_cb (GtkWidget
* button
, ConfigColor
* cc
)
1820 HID_Attribute
*ha
= cc
->attributes
;
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();
1839 config_color_button_create (GtkWidget
* box
, ConfigColor
* cc
)
1841 GtkWidget
*button
, *hbox
, *label
;
1842 HID_Attribute
*ha
= cc
->attributes
;
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
);
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
);
1865 config_colors_tab_create (GtkWidget
* tab_vbox
)
1867 GtkWidget
*scrolled_vbox
, *vbox
, *hbox
, *expander
, *sep
;
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
)
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
)
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
)
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
)
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
,
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
,
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 -----------------
1976 static GtkNotebook
*config_notebook
;
1979 config_page_create (GtkTreeStore
* tree
, GtkTreeIter
* iter
,
1980 GtkNotebook
* notebook
)
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);
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
);
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
;
2017 ghid_config_text_scale_update (void)
2020 gtk_spin_button_set_value (GTK_SPIN_BUTTON (config_text_spin_button
),
2021 (gdouble
) Settings
.TextScale
);
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
;
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
;
2057 config_selection_changed_cb (GtkTreeSelection
* selection
, gpointer data
)
2060 GtkTreeModel
*model
;
2063 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
))
2065 gtk_tree_model_get (model
, &iter
, CONFIG_PAGE_COLUMN
, &page
, -1);
2066 gtk_notebook_set_current_page (config_notebook
, page
);
2070 ghid_config_window_show (void)
2072 GtkWidget
*widget
, *main_vbox
, *vbox
, *config_hbox
, *hbox
;
2073 GtkWidget
*scrolled
;
2075 GtkTreeStore
*model
;
2076 GtkTreeView
*treeview
;
2078 GtkCellRenderer
*renderer
;
2079 GtkTreeViewColumn
*column
;
2080 GtkTreeSelection
*select
;
2084 gtk_window_present (GTK_WINDOW (config_window
));
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
);
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
);
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
);
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
);
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
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
,
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
);