1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1999 Alexander Larsson
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #include <sys/types.h>
44 #include "preferences.h"
47 struct DiaPreferences prefs
;
61 enum DiaPrefType type
;
69 static int default_true
= 1;
70 static int default_false
= 0;
71 static real default_real_one
= 1.0;
72 static real default_real_zoom
= 100.0;
73 static int default_int_w
= 500;
74 static int default_int_h
= 400;
75 static int default_undo_depth
= 15;
76 static Color default_colour
= { 0.5, 0.5, 0.5 };
77 static Color pbreak_colour
= { 0.0, 0.0, 0.6 };
85 struct DiaPrefsTab prefs_tabs
[] =
87 {N_("User Interface"), NULL
, 0},
88 {N_("View Defaults"), NULL
, 0},
89 {N_("Grid Lines"), NULL
, 0},
92 #define NUM_PREFS_TABS (sizeof(prefs_tabs)/sizeof(struct DiaPrefsTab))
94 /* retrive a structure offset */
96 #define PREF_OFFSET(field) ((int) offsetof (struct DiaPreferences, field))
98 #define PREF_OFFSET(field) ((int) ((char*) &((struct DiaPreferences *) 0)->field))
99 #endif /* !offsetof */
101 struct DiaPrefsData prefs_data
[] =
103 { "reset_tools_after_create", PREF_BOOLEAN
, PREF_OFFSET(reset_tools_after_create
), &default_true
, 0, N_("Reset tools after create:") },
104 { "compress_save", PREF_BOOLEAN
, PREF_OFFSET(compress_save
), &default_true
, 0, N_("Compress saved files:") },
105 { "undo_depth", PREF_UINT
, PREF_OFFSET(undo_depth
), &default_undo_depth
, 0, N_("Number of undo levels:") },
106 { "reverse_rubberbanding_intersects", PREF_BOOLEAN
, PREF_OFFSET(reverse_rubberbanding_intersects
), &default_true
, 0, N_("Reverse dragging selects\nintersecting objects:") },
107 { NULL
, PREF_NONE
, 0, NULL
, 1, N_("New window:") },
108 { "new_view_width", PREF_UINT
, PREF_OFFSET(new_view
.width
), &default_int_w
, 1, N_("Width:") },
109 { "new_view_height", PREF_UINT
, PREF_OFFSET(new_view
.height
), &default_int_h
, 1, N_("Height:") },
110 { "new_view_zoom", PREF_UREAL
, PREF_OFFSET(new_view
.zoom
), &default_real_zoom
, 1, N_("Magnify:") },
112 { NULL
, PREF_NONE
, 0, NULL
, 1, N_("Connection Points:") },
113 { "show_cx_pts", PREF_BOOLEAN
, PREF_OFFSET(show_cx_pts
), &default_true
, 1, N_("Visible:") },
115 { NULL
, PREF_NONE
, 0, NULL
, 2, N_("Grid:") },
116 { "grid_visible", PREF_BOOLEAN
, PREF_OFFSET(grid
.visible
), &default_true
, 2, N_("Visible:") },
117 { "grid_snap", PREF_BOOLEAN
, PREF_OFFSET(grid
.snap
), &default_false
, 2, N_("Snap to:") },
118 { "grid_x", PREF_UREAL
, PREF_OFFSET(grid
.x
), &default_real_one
, 2, N_("X Size:") },
119 { "grid_y", PREF_UREAL
, PREF_OFFSET(grid
.y
), &default_real_one
, 2, N_("Y Size:") },
120 { "grid_colour", PREF_COLOUR
, PREF_OFFSET(grid
.colour
), &default_colour
, 2, N_("Colour:") },
121 { "grid_solid", PREF_BOOLEAN
, PREF_OFFSET(grid
.solid
), &default_true
, 2, N_("Solid lines:") },
123 { NULL
, PREF_NONE
, 0, NULL
, 2, N_("Page breaks:") },
124 { "pagebreak_visible", PREF_BOOLEAN
, PREF_OFFSET(pagebreak
.visible
), &default_true
, 2, N_("Visible:") },
125 { "pagebreak_colour", PREF_COLOUR
, PREF_OFFSET(pagebreak
.colour
), &pbreak_colour
, 2, N_("Colour:") },
126 { "pagebreak_solid", PREF_BOOLEAN
, PREF_OFFSET(pagebreak
.solid
), &default_true
, 2, N_("Solid lines:") },
129 #define NUM_PREFS_DATA (sizeof(prefs_data)/sizeof(struct DiaPrefsData))
131 static const GScannerConfig dia_prefs_scanner_config
=
135 ) /* cset_skip_characters */,
140 ) /* cset_identifier_first */,
145 ) /* cset_identifier_nth */,
146 ( "#\n" ) /* cpair_comment_single */,
148 TRUE
/* case_sensitive */,
150 FALSE
/* skip_comment_multi */,
151 TRUE
/* skip_comment_single */,
152 FALSE
/* scan_comment_multi */,
153 TRUE
/* scan_identifier */,
154 TRUE
/* scan_identifier_1char */,
155 FALSE
/* scan_identifier_NULL */,
156 TRUE
/* scan_symbols */,
157 FALSE
/* scan_binary */,
158 FALSE
/* scan_octal */,
159 TRUE
/* scan_float */,
161 FALSE
/* scan_hex_dollar */,
162 FALSE
/* scan_string_sq */,
163 TRUE
/* scan_string_dq */,
164 TRUE
/* numbers_2_int */,
165 FALSE
/* int_2_float */,
166 FALSE
/* identifier_2_string */,
167 TRUE
/* char_2_token */,
168 FALSE
/* symbol_2_token */,
169 FALSE
/* scope_0_fallback */,
173 DIA_PREFS_TOKEN_BOOLEAN
= G_TOKEN_LAST
176 static void prefs_create_dialog(void);
177 static void prefs_set_value_in_widget(GtkWidget
* widget
, enum DiaPrefType type
, char *ptr
);
178 static void prefs_get_value_from_widget(GtkWidget
* widget
, enum DiaPrefType type
, char *ptr
);
179 static void prefs_update_dialog_from_prefs(void);
180 static void prefs_update_prefs_from_dialog(void);
181 static gint
prefs_apply(GtkWidget
*widget
, gpointer data
);
184 static GtkWidget
*prefs_dialog
= NULL
;
189 prefs_create_dialog();
190 gtk_widget_show(prefs_dialog
);
192 prefs_update_dialog_from_prefs();
196 prefs_set_defaults(void)
201 for (i
=0;i
<NUM_PREFS_DATA
;i
++) {
202 ptr
= (char *)&prefs
+ prefs_data
[i
].offset
;
204 switch (prefs_data
[i
].type
) {
208 *(int *)ptr
= *(int *)prefs_data
[i
].default_value
;
212 *(real
*)ptr
= *(real
*)prefs_data
[i
].default_value
;
215 *(Color
*)ptr
= *(Color
*)prefs_data
[i
].default_value
;
232 filename
= dia_config_filename("diarc");
234 file
= fopen(filename
, "w");
237 message_error(_("Could not open `%s' for writing"), filename
);
244 old_locale
= setlocale(LC_NUMERIC
, "C");
245 fprintf(file
, "# Note: This file is automatically generated by Dia\n");
246 for (i
=0;i
<NUM_PREFS_DATA
;i
++) {
247 if (prefs_data
[i
].type
== PREF_NONE
)
250 fprintf(file
, "%s=", prefs_data
[i
].name
);
252 ptr
= (char *)&prefs
+ prefs_data
[i
].offset
;
254 switch (prefs_data
[i
].type
) {
256 fprintf(file
, (*(int *)ptr
)?"true\n":"false\n");
260 fprintf(file
, "%d\n", *(int *)ptr
);
265 fprintf(file
, "%f\n", (double) *(real
*)ptr
);
268 fprintf(file
, "%f %f %f\n", (double) ((Color
*)ptr
)->red
,
269 (double) ((Color
*)ptr
)->green
, (double) ((Color
*)ptr
)->blue
);
274 setlocale(LC_NUMERIC
, old_locale
);
280 prefs_parse_line(GScanner
*scanner
)
286 token
= g_scanner_get_next_token(scanner
);
287 if (token
!= G_TOKEN_SYMBOL
)
288 return G_TOKEN_SYMBOL
;
290 symbol_nr
= GPOINTER_TO_INT(scanner
->value
.v_symbol
);
292 token
= g_scanner_get_next_token(scanner
);
293 if (token
!= G_TOKEN_EQUAL_SIGN
)
294 return G_TOKEN_EQUAL_SIGN
;
296 token
= g_scanner_get_next_token(scanner
);
298 ptr
= (unsigned char *)&prefs
+ prefs_data
[symbol_nr
].offset
;
300 switch (prefs_data
[symbol_nr
].type
) {
302 if (token
!= G_TOKEN_IDENTIFIER
)
303 return G_TOKEN_IDENTIFIER
;
305 if (strcmp(scanner
->value
.v_string
, "true")==0)
313 if (token
!= G_TOKEN_INT
)
316 *(int *)ptr
= scanner
->value
.v_int
;
321 if (token
!= G_TOKEN_FLOAT
)
322 return G_TOKEN_FLOAT
;
324 *(real
*)ptr
= scanner
->value
.v_float
;
327 if (token
!= G_TOKEN_FLOAT
)
328 return G_TOKEN_FLOAT
;
329 ((Color
*)ptr
)->red
= scanner
->value
.v_float
;
331 token
= g_scanner_get_next_token(scanner
);
332 if (token
!= G_TOKEN_FLOAT
)
333 return G_TOKEN_FLOAT
;
334 ((Color
*)ptr
)->green
= scanner
->value
.v_float
;
336 token
= g_scanner_get_next_token(scanner
);
337 if (token
!= G_TOKEN_FLOAT
)
338 return G_TOKEN_FLOAT
;
339 ((Color
*)ptr
)->blue
= scanner
->value
.v_float
;
357 guint expected_token
;
359 filename
= dia_config_filename("diarc");
361 fd
= open(filename
, O_RDONLY
);
364 char *homedir
= g_get_home_dir();
367 filename
= g_strconcat(homedir
, G_DIR_SEPARATOR_S
".diarc", NULL
);
368 fd
= open(filename
, O_RDONLY
);
372 prefs_set_defaults();
378 scanner
= g_scanner_new ((GScannerConfig
*) &dia_prefs_scanner_config
);
380 g_scanner_input_file (scanner
, fd
);
382 scanner
->input_name
= filename
;
384 g_scanner_freeze_symbol_table(scanner
);
385 for (i
= 0; i
< NUM_PREFS_DATA
; i
++)
386 if (prefs_data
[i
].type
!= PREF_NONE
) {
387 g_scanner_add_symbol(scanner
, prefs_data
[i
].name
,
390 g_scanner_thaw_symbol_table(scanner
);
393 if (g_scanner_peek_next_token(scanner
) == G_TOKEN_EOF
) {
397 expected_token
= prefs_parse_line(scanner
);
399 if (expected_token
!= G_TOKEN_NONE
) {
405 g_scanner_unexp_token (scanner
,
415 g_scanner_destroy (scanner
);
421 prefs_okay(GtkWidget
*widget
, gpointer data
)
423 gint ret
= prefs_apply(widget
,data
);
424 gtk_widget_hide(widget
);
429 prefs_apply(GtkWidget
*widget
, gpointer data
)
431 prefs_update_prefs_from_dialog();
433 diagram_redraw_all();
438 prefs_set_value_in_widget(GtkWidget
* widget
, enum DiaPrefType type
,
443 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget
), *((int *)ptr
));
447 gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget
),
448 (gfloat
) (*((int *)ptr
)));
452 gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget
),
453 (gfloat
) (*((real
*)ptr
)));
456 dia_color_selector_set_color(DIACOLORSELECTOR(widget
), (Color
*)ptr
);
464 prefs_get_value_from_widget(GtkWidget
* widget
, enum DiaPrefType type
,
469 *((int *)ptr
) = GTK_TOGGLE_BUTTON(widget
)->active
;
474 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget
));
478 *((real
*)ptr
) = (real
)
479 gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(widget
));
482 dia_color_selector_get_color(DIACOLORSELECTOR(widget
), (Color
*)ptr
);
490 prefs_boolean_toggle(GtkWidget
*widget
, gpointer data
)
492 guint active
= GTK_TOGGLE_BUTTON(widget
)->active
;
493 GtkWidget
*label
= GTK_BUTTON(widget
)->child
;
494 gtk_label_set(GTK_LABEL(label
), active
? _("Yes") : _("No"));
498 prefs_get_property_widget(enum DiaPrefType type
)
500 GtkWidget
*widget
= NULL
;
505 widget
= gtk_toggle_button_new_with_label (_("No"));
506 gtk_signal_connect (GTK_OBJECT (widget
), "toggled",
507 GTK_SIGNAL_FUNC (prefs_boolean_toggle
), NULL
);
510 adj
= GTK_ADJUSTMENT(gtk_adjustment_new(0.0,
513 widget
= gtk_spin_button_new (adj
, 1.0, 0);
514 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget
), TRUE
);
515 gtk_widget_set_usize(widget
, 80, -1);
518 adj
= GTK_ADJUSTMENT(gtk_adjustment_new(0.0,
521 widget
= gtk_spin_button_new (adj
, 1.0, 0);
522 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget
), TRUE
);
523 gtk_widget_set_usize(widget
, 80, -1);
526 adj
= GTK_ADJUSTMENT(gtk_adjustment_new(0.0,
527 G_MINFLOAT
, G_MAXFLOAT
,
529 widget
= gtk_spin_button_new (adj
, 1.0, 3);
530 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget
), TRUE
);
531 gtk_widget_set_usize(widget
, 80, -1);
534 adj
= GTK_ADJUSTMENT(gtk_adjustment_new(0.0,
537 widget
= gtk_spin_button_new (adj
, 1.0, 3);
538 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget
), TRUE
);
539 gtk_widget_set_usize(widget
, 80, -1);
542 widget
= dia_color_selector_new();
549 gtk_widget_show(widget
);
554 prefs_create_dialog(void)
556 GtkWidget
*notebook_page
;
561 GtkWidget
*dialog_vbox
;
566 if (prefs_dialog
!= NULL
)
570 prefs_dialog
= gnome_dialog_new(_("Preferences"),
571 GNOME_STOCK_BUTTON_OK
,
572 GNOME_STOCK_BUTTON_APPLY
,
573 GNOME_STOCK_BUTTON_CLOSE
, NULL
);
574 gnome_dialog_set_default(GNOME_DIALOG(prefs_dialog
), 1);
576 dialog_vbox
= GNOME_DIALOG(prefs_dialog
)->vbox
;
578 prefs_dialog
= gtk_dialog_new();
579 gtk_window_set_title (GTK_WINDOW (prefs_dialog
), _("Preferences"));
580 gtk_container_set_border_width (GTK_CONTAINER (prefs_dialog
), 2);
581 gtk_window_set_policy (GTK_WINDOW (prefs_dialog
),
584 dialog_vbox
= GTK_DIALOG (prefs_dialog
)->vbox
;
587 gtk_window_set_wmclass (GTK_WINDOW (prefs_dialog
),
588 "preferences_window", "Dia");
592 gnome_dialog_button_connect_object(GNOME_DIALOG(prefs_dialog
), 0,
593 GTK_SIGNAL_FUNC(prefs_okay
),
594 GTK_OBJECT(prefs_dialog
));
595 gnome_dialog_button_connect_object(GNOME_DIALOG(prefs_dialog
), 1,
596 GTK_SIGNAL_FUNC(prefs_apply
),
597 GTK_OBJECT(prefs_dialog
));
598 gnome_dialog_button_connect_object(GNOME_DIALOG(prefs_dialog
), 2,
599 GTK_SIGNAL_FUNC(gtk_widget_hide
),
600 GTK_OBJECT(prefs_dialog
));
602 button
= gtk_button_new_with_label( _("OK") );
603 GTK_WIDGET_SET_FLAGS (button
, GTK_CAN_DEFAULT
);
604 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (prefs_dialog
)->action_area
),
605 button
, TRUE
, TRUE
, 0);
606 gtk_signal_connect_object (GTK_OBJECT (button
), "clicked",
607 GTK_SIGNAL_FUNC(prefs_okay
),
608 GTK_OBJECT(prefs_dialog
));
609 gtk_widget_show (button
);
611 button
= gtk_button_new_with_label( _("Apply") );
612 GTK_WIDGET_SET_FLAGS (button
, GTK_CAN_DEFAULT
);
613 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (prefs_dialog
)->action_area
),
614 button
, TRUE
, TRUE
, 0);
615 gtk_signal_connect (GTK_OBJECT (button
), "clicked",
616 GTK_SIGNAL_FUNC(prefs_apply
),
618 gtk_widget_show (button
);
620 button
= gtk_button_new_with_label( _("Close") );
621 GTK_WIDGET_SET_FLAGS (button
, GTK_CAN_DEFAULT
);
622 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (prefs_dialog
)->action_area
),
623 button
, TRUE
, TRUE
, 0);
624 gtk_signal_connect_object (GTK_OBJECT (button
), "clicked",
625 GTK_SIGNAL_FUNC(gtk_widget_hide
),
626 GTK_OBJECT(prefs_dialog
));
627 gtk_widget_grab_default (button
);
628 gtk_widget_show (button
);
631 gtk_signal_connect (GTK_OBJECT (prefs_dialog
), "delete_event",
632 GTK_SIGNAL_FUNC(gtk_widget_hide
), NULL
);
634 notebook
= gtk_notebook_new ();
635 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook
), GTK_POS_TOP
);
636 gtk_box_pack_start (GTK_BOX (dialog_vbox
), notebook
, TRUE
, TRUE
, 0);
637 gtk_container_set_border_width (GTK_CONTAINER (notebook
), 2);
638 gtk_widget_show (notebook
);
640 for (i
=0;i
<NUM_PREFS_TABS
;i
++) {
641 label
= gtk_label_new(gettext(prefs_tabs
[i
].title
));
642 gtk_widget_show(label
);
644 table
= gtk_table_new (9, 2, FALSE
);
645 prefs_tabs
[i
].table
= GTK_TABLE(table
);
646 gtk_widget_show(table
);
648 #ifdef SCROLLED_PAGES
649 notebook_page
= gtk_scrolled_window_new (NULL
, NULL
);
650 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (notebook_page
),
651 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
652 gtk_widget_show(notebook_page
);
654 notebook_page
= table
;
655 #endif/* SCROLLED_PAGES */
657 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), notebook_page
, label
);
659 #ifdef SCROLLED_PAGES
660 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(notebook_page
),
662 gtk_viewport_set_shadow_type(GTK_VIEWPORT(GTK_BIN(notebook_page
)->child
),
664 #endif /* SCROLLED_PAGES */
668 for (i
=0;i
<NUM_PREFS_DATA
;i
++) {
673 label
= gtk_label_new (gettext(prefs_data
[i
].label_text
));
674 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.3);
675 gtk_widget_show (label
);
677 table
= prefs_tabs
[prefs_data
[i
].tab
].table
;
678 row
= prefs_tabs
[prefs_data
[i
].tab
].row
++;
679 gtk_table_attach (table
, label
, 0, 1,
681 GTK_FILL
, GTK_FILL
, 1, 1);
683 widget
= prefs_get_property_widget(prefs_data
[i
].type
);
684 prefs_data
[i
].widget
= widget
;
685 if (widget
!= NULL
) {
686 gtk_table_attach (table
, widget
, 1, 2,
688 GTK_EXPAND
| GTK_FILL
, GTK_FILL
, 1, 1);
693 gtk_widget_show (prefs_dialog
);
697 prefs_update_prefs_from_dialog(void)
703 for (i
=0;i
<NUM_PREFS_DATA
;i
++) {
704 widget
= prefs_data
[i
].widget
;
705 ptr
= (char *)&prefs
+ prefs_data
[i
].offset
;
707 prefs_get_value_from_widget(widget
, prefs_data
[i
].type
, ptr
);
712 prefs_update_dialog_from_prefs(void)
718 for (i
=0;i
<NUM_PREFS_DATA
;i
++) {
719 widget
= prefs_data
[i
].widget
;
720 ptr
= (char *)&prefs
+ prefs_data
[i
].offset
;
722 prefs_set_value_in_widget(widget
, prefs_data
[i
].type
, ptr
);