/* Dia -- an diagram creation/manipulation program * Copyright (C) 1999 Alexander Larsson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include #include #include #include #include #include #include #ifdef HAVE_STDDEF_H #include #endif #include #ifdef GNOME # include #else # include #endif #include "intl.h" #include "widgets.h" #include "diagram.h" #include "message.h" #include "preferences.h" #include "dia_dirs.h" struct DiaPreferences prefs; enum DiaPrefType { PREF_NONE, PREF_BOOLEAN, PREF_INT, PREF_UINT, PREF_REAL, PREF_UREAL, PREF_COLOUR }; struct DiaPrefsData { char *name; enum DiaPrefType type; int offset; void *default_value; int tab; char *label_text; GtkWidget *widget; }; static int default_true = 1; static int default_false = 0; static real default_real_one = 1.0; static real default_real_zoom = 100.0; static int default_int_w = 500; static int default_int_h = 400; static int default_undo_depth = 15; static Color default_colour = { 0.5, 0.5, 0.5 }; static Color pbreak_colour = { 0.0, 0.0, 0.6 }; struct DiaPrefsTab { char *title; GtkTable *table; int row; }; struct DiaPrefsTab prefs_tabs[] = { {N_("User Interface"), NULL, 0}, {N_("View Defaults"), NULL, 0}, {N_("Grid Lines"), NULL, 0}, }; #define NUM_PREFS_TABS (sizeof(prefs_tabs)/sizeof(struct DiaPrefsTab)) /* retrive a structure offset */ #ifdef offsetof #define PREF_OFFSET(field) ((int) offsetof (struct DiaPreferences, field)) #else /* !offsetof */ #define PREF_OFFSET(field) ((int) ((char*) &((struct DiaPreferences *) 0)->field)) #endif /* !offsetof */ struct DiaPrefsData prefs_data[] = { { "reset_tools_after_create", PREF_BOOLEAN, PREF_OFFSET(reset_tools_after_create), &default_true, 0, N_("Reset tools after create:") }, { "compress_save", PREF_BOOLEAN, PREF_OFFSET(compress_save), &default_true, 0, N_("Compress saved files:") }, { "undo_depth", PREF_UINT, PREF_OFFSET(undo_depth), &default_undo_depth, 0, N_("Number of undo levels:") }, { "reverse_rubberbanding_intersects", PREF_BOOLEAN, PREF_OFFSET(reverse_rubberbanding_intersects), &default_true, 0, N_("Reverse dragging selects\nintersecting objects:") }, { NULL, PREF_NONE, 0, NULL, 1, N_("New window:") }, { "new_view_width", PREF_UINT, PREF_OFFSET(new_view.width), &default_int_w, 1, N_("Width:") }, { "new_view_height", PREF_UINT, PREF_OFFSET(new_view.height), &default_int_h, 1, N_("Height:") }, { "new_view_zoom", PREF_UREAL, PREF_OFFSET(new_view.zoom), &default_real_zoom, 1, N_("Magnify:") }, { NULL, PREF_NONE, 0, NULL, 1, N_("Connection Points:") }, { "show_cx_pts", PREF_BOOLEAN, PREF_OFFSET(show_cx_pts), &default_true, 1, N_("Visible:") }, { NULL, PREF_NONE, 0, NULL, 2, N_("Grid:") }, { "grid_visible", PREF_BOOLEAN, PREF_OFFSET(grid.visible), &default_true, 2, N_("Visible:") }, { "grid_snap", PREF_BOOLEAN, PREF_OFFSET(grid.snap), &default_false, 2, N_("Snap to:") }, { "grid_x", PREF_UREAL, PREF_OFFSET(grid.x), &default_real_one, 2, N_("X Size:") }, { "grid_y", PREF_UREAL, PREF_OFFSET(grid.y), &default_real_one, 2, N_("Y Size:") }, { "grid_colour", PREF_COLOUR, PREF_OFFSET(grid.colour), &default_colour, 2, N_("Colour:") }, { "grid_solid", PREF_BOOLEAN, PREF_OFFSET(grid.solid), &default_true, 2, N_("Solid lines:") }, { NULL, PREF_NONE, 0, NULL, 2, N_("Page breaks:") }, { "pagebreak_visible", PREF_BOOLEAN, PREF_OFFSET(pagebreak.visible), &default_true, 2, N_("Visible:") }, { "pagebreak_colour", PREF_COLOUR, PREF_OFFSET(pagebreak.colour), &pbreak_colour, 2, N_("Colour:") }, { "pagebreak_solid", PREF_BOOLEAN, PREF_OFFSET(pagebreak.solid), &default_true, 2, N_("Solid lines:") }, }; #define NUM_PREFS_DATA (sizeof(prefs_data)/sizeof(struct DiaPrefsData)) static const GScannerConfig dia_prefs_scanner_config = { ( " \t\n" ) /* cset_skip_characters */, ( G_CSET_a_2_z "_" G_CSET_A_2_Z ) /* cset_identifier_first */, ( G_CSET_a_2_z "_-0123456789" G_CSET_A_2_Z ) /* cset_identifier_nth */, ( "#\n" ) /* cpair_comment_single */, TRUE /* case_sensitive */, FALSE /* skip_comment_multi */, TRUE /* skip_comment_single */, FALSE /* scan_comment_multi */, TRUE /* scan_identifier */, TRUE /* scan_identifier_1char */, FALSE /* scan_identifier_NULL */, TRUE /* scan_symbols */, FALSE /* scan_binary */, FALSE /* scan_octal */, TRUE /* scan_float */, TRUE /* scan_hex */, FALSE /* scan_hex_dollar */, FALSE /* scan_string_sq */, TRUE /* scan_string_dq */, TRUE /* numbers_2_int */, FALSE /* int_2_float */, FALSE /* identifier_2_string */, TRUE /* char_2_token */, FALSE /* symbol_2_token */, FALSE /* scope_0_fallback */, }; typedef enum { DIA_PREFS_TOKEN_BOOLEAN = G_TOKEN_LAST } DiaPrefsTokenType; static void prefs_create_dialog(void); static void prefs_set_value_in_widget(GtkWidget * widget, enum DiaPrefType type, char *ptr); static void prefs_get_value_from_widget(GtkWidget * widget, enum DiaPrefType type, char *ptr); static void prefs_update_dialog_from_prefs(void); static void prefs_update_prefs_from_dialog(void); static gint prefs_apply(GtkWidget *widget, gpointer data); static GtkWidget *prefs_dialog = NULL; void prefs_show(void) { prefs_create_dialog(); gtk_widget_show(prefs_dialog); prefs_update_dialog_from_prefs(); } void prefs_set_defaults(void) { int i; char *ptr; for (i=0;ired, (double) ((Color *)ptr)->green, (double) ((Color *)ptr)->blue); case PREF_NONE: break; } } setlocale(LC_NUMERIC, old_locale); fclose(file); } static guint prefs_parse_line(GScanner *scanner) { guint token; int symbol_nr; char *ptr; token = g_scanner_get_next_token(scanner); if (token != G_TOKEN_SYMBOL) return G_TOKEN_SYMBOL; symbol_nr = GPOINTER_TO_INT(scanner->value.v_symbol); token = g_scanner_get_next_token(scanner); if (token != G_TOKEN_EQUAL_SIGN) return G_TOKEN_EQUAL_SIGN; token = g_scanner_get_next_token(scanner); ptr = (unsigned char *)&prefs + prefs_data[symbol_nr].offset; switch (prefs_data[symbol_nr].type) { case PREF_BOOLEAN: if (token != G_TOKEN_IDENTIFIER) return G_TOKEN_IDENTIFIER; if (strcmp(scanner->value.v_string, "true")==0) *(int *)ptr = 1; else *(int *)ptr = 0; break; case PREF_INT: case PREF_UINT: if (token != G_TOKEN_INT) return G_TOKEN_INT; *(int *)ptr = scanner->value.v_int; break; case PREF_REAL: case PREF_UREAL: if (token != G_TOKEN_FLOAT) return G_TOKEN_FLOAT; *(real *)ptr = scanner->value.v_float; break; case PREF_COLOUR: if (token != G_TOKEN_FLOAT) return G_TOKEN_FLOAT; ((Color *)ptr)->red = scanner->value.v_float; token = g_scanner_get_next_token(scanner); if (token != G_TOKEN_FLOAT) return G_TOKEN_FLOAT; ((Color *)ptr)->green = scanner->value.v_float; token = g_scanner_get_next_token(scanner); if (token != G_TOKEN_FLOAT) return G_TOKEN_FLOAT; ((Color *)ptr)->blue = scanner->value.v_float; break; case PREF_NONE: break; } return G_TOKEN_NONE; } void prefs_load(void) { int i; gchar *filename; int fd; GScanner *scanner; guint expected_token; filename = dia_config_filename("diarc"); fd = open(filename, O_RDONLY); if (fd < 0) { char *homedir = g_get_home_dir(); g_free(filename); filename = g_strconcat(homedir, G_DIR_SEPARATOR_S ".diarc", NULL); fd = open(filename, O_RDONLY); } g_free(filename); prefs_set_defaults(); if (fd < 0) { return; } scanner = g_scanner_new ((GScannerConfig *) &dia_prefs_scanner_config); g_scanner_input_file (scanner, fd); scanner->input_name = filename; g_scanner_freeze_symbol_table(scanner); for (i = 0; i < NUM_PREFS_DATA; i++) if (prefs_data[i].type != PREF_NONE) { g_scanner_add_symbol(scanner, prefs_data[i].name, GINT_TO_POINTER(i)); } g_scanner_thaw_symbol_table(scanner); while (1) { if (g_scanner_peek_next_token(scanner) == G_TOKEN_EOF) { break; } expected_token = prefs_parse_line(scanner); if (expected_token != G_TOKEN_NONE) { gchar *symbol_name; gchar *msg; msg = NULL; symbol_name = NULL; g_scanner_unexp_token (scanner, expected_token, NULL, "keyword", symbol_name, msg, TRUE); } } g_scanner_destroy (scanner); close(fd); } static gint prefs_okay(GtkWidget *widget, gpointer data) { gint ret = prefs_apply(widget,data); gtk_widget_hide(widget); return ret; } static gint prefs_apply(GtkWidget *widget, gpointer data) { prefs_update_prefs_from_dialog(); prefs_save(); diagram_redraw_all(); return 1; } static void prefs_set_value_in_widget(GtkWidget * widget, enum DiaPrefType type, char *ptr) { switch(type) { case PREF_BOOLEAN: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), *((int *)ptr)); break; case PREF_INT: case PREF_UINT: gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), (gfloat) (*((int *)ptr))); break; case PREF_REAL: case PREF_UREAL: gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), (gfloat) (*((real *)ptr))); break; case PREF_COLOUR: dia_color_selector_set_color(DIACOLORSELECTOR(widget), (Color *)ptr); break; case PREF_NONE: break; } } static void prefs_get_value_from_widget(GtkWidget * widget, enum DiaPrefType type, char *ptr) { switch(type) { case PREF_BOOLEAN: *((int *)ptr) = GTK_TOGGLE_BUTTON(widget)->active; break; case PREF_INT: case PREF_UINT: *((int *)ptr) = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)); break; case PREF_REAL: case PREF_UREAL: *((real *)ptr) = (real) gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(widget)); break; case PREF_COLOUR: dia_color_selector_get_color(DIACOLORSELECTOR(widget), (Color *)ptr); break; case PREF_NONE: break; } } static void prefs_boolean_toggle(GtkWidget *widget, gpointer data) { guint active = GTK_TOGGLE_BUTTON(widget)->active; GtkWidget *label = GTK_BUTTON(widget)->child; gtk_label_set(GTK_LABEL(label), active ? _("Yes") : _("No")); } static GtkWidget * prefs_get_property_widget(enum DiaPrefType type) { GtkWidget *widget = NULL; GtkAdjustment *adj; switch(type) { case PREF_BOOLEAN: widget = gtk_toggle_button_new_with_label (_("No")); gtk_signal_connect (GTK_OBJECT (widget), "toggled", GTK_SIGNAL_FUNC (prefs_boolean_toggle), NULL); break; case PREF_INT: adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, G_MININT, G_MAXINT, 1.0, 10.0, 10.0 )); widget = gtk_spin_button_new (adj, 1.0, 0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), TRUE); gtk_widget_set_usize(widget, 80, -1); break; case PREF_UINT: adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, G_MAXINT, 1.0, 10.0, 10.0 )); widget = gtk_spin_button_new (adj, 1.0, 0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), TRUE); gtk_widget_set_usize(widget, 80, -1); break; case PREF_REAL: adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, G_MINFLOAT, G_MAXFLOAT, 1.0, 10.0, 10.0 )); widget = gtk_spin_button_new (adj, 1.0, 3); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), TRUE); gtk_widget_set_usize(widget, 80, -1); break; case PREF_UREAL: adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, G_MAXFLOAT, 1.0, 10.0, 10.0 )); widget = gtk_spin_button_new (adj, 1.0, 3); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), TRUE); gtk_widget_set_usize(widget, 80, -1); break; case PREF_COLOUR: widget = dia_color_selector_new(); break; case PREF_NONE: widget = NULL; break; } if (widget != NULL) gtk_widget_show(widget); return widget; } static void prefs_create_dialog(void) { GtkWidget *notebook_page; GtkWidget *label; GtkWidget *button; GtkWidget *dialog_vbox; GtkWidget *notebook; GtkWidget *table; int i; if (prefs_dialog != NULL) return; #ifdef GNOME prefs_dialog = gnome_dialog_new(_("Preferences"), GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_APPLY, GNOME_STOCK_BUTTON_CLOSE, NULL); gnome_dialog_set_default(GNOME_DIALOG(prefs_dialog), 1); dialog_vbox = GNOME_DIALOG(prefs_dialog)->vbox; #else prefs_dialog = gtk_dialog_new(); gtk_window_set_title (GTK_WINDOW (prefs_dialog), _("Preferences")); gtk_container_set_border_width (GTK_CONTAINER (prefs_dialog), 2); gtk_window_set_policy (GTK_WINDOW (prefs_dialog), FALSE, TRUE, FALSE); dialog_vbox = GTK_DIALOG (prefs_dialog)->vbox; #endif gtk_window_set_wmclass (GTK_WINDOW (prefs_dialog), "preferences_window", "Dia"); #ifdef GNOME gnome_dialog_button_connect_object(GNOME_DIALOG(prefs_dialog), 0, GTK_SIGNAL_FUNC(prefs_okay), GTK_OBJECT(prefs_dialog)); gnome_dialog_button_connect_object(GNOME_DIALOG(prefs_dialog), 1, GTK_SIGNAL_FUNC(prefs_apply), GTK_OBJECT(prefs_dialog)); gnome_dialog_button_connect_object(GNOME_DIALOG(prefs_dialog), 2, GTK_SIGNAL_FUNC(gtk_widget_hide), GTK_OBJECT(prefs_dialog)); #else button = gtk_button_new_with_label( _("OK") ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (prefs_dialog)->action_area), button, TRUE, TRUE, 0); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC(prefs_okay), GTK_OBJECT(prefs_dialog)); gtk_widget_show (button); button = gtk_button_new_with_label( _("Apply") ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (prefs_dialog)->action_area), button, TRUE, TRUE, 0); gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC(prefs_apply), NULL); gtk_widget_show (button); button = gtk_button_new_with_label( _("Close") ); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (prefs_dialog)->action_area), button, TRUE, TRUE, 0); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_hide), GTK_OBJECT(prefs_dialog)); gtk_widget_grab_default (button); gtk_widget_show (button); #endif gtk_signal_connect (GTK_OBJECT (prefs_dialog), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_hide), NULL); notebook = gtk_notebook_new (); gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP); gtk_box_pack_start (GTK_BOX (dialog_vbox), notebook, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (notebook), 2); gtk_widget_show (notebook); for (i=0;ichild), GTK_SHADOW_NONE); #endif /* SCROLLED_PAGES */ } for (i=0;i