1 /* Dia -- an diagram creation/manipulation program
2  * Copyright (C) 1999 Alexander Larsson
3  *
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.
8  *
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.
13  *
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.
17  */
18 #include <config.h>
19 
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27 #ifdef HAVE_STDDEF_H
28 #include <stddef.h>
29 #endif
30 
31 #include <gtk/gtk.h>
32 
33 #include "intl.h"
34 #include "widgets.h"
35 #include "diagram.h"
36 #include "message.h"
37 #include "preferences.h"
38 #include "dia_dirs.h"
39 #include "diagramdata.h"
40 #include "paper.h"
41 #include "interface.h"
42 #include "lib/prefs.h"
43 #include "persistence.h"
44 
45 #ifdef G_OS_WIN32
46 #include <io.h> /* open, close */
47 #endif
48 
49 struct DiaPreferences prefs;
50 
51 enum DiaPrefType {
52   PREF_NONE,
53   PREF_BOOLEAN,
54   PREF_INT,
55   PREF_UINT,
56   PREF_REAL,
57   PREF_UREAL,
58   PREF_COLOUR,
59   PREF_CHOICE,
60   PREF_STRING,
61   PREF_END_GROUP
62 };
63 
64 typedef struct _DiaPrefData {
65   char *name;
66   enum DiaPrefType type;
67   int offset;
68   const void *default_value;
69   int tab;
70   char *label_text;
71   GtkWidget *widget;
72   gboolean hidden;
73   GList *(*choice_list_function)(struct _DiaPrefData *pref);
74   /** A function to call after a preference item has been updated. */
75   void (*update_function)(struct _DiaPrefData *pref, gpointer ptr);
76   const char *key;
77 } DiaPrefData;
78 
79 static void update_floating_toolbox(DiaPrefData *pref, gpointer ptr);
80 static void update_internal_prefs(DiaPrefData *pref, gpointer ptr);
81 
82 static int default_true = 1;
83 static int default_false = 0;
84 static int default_major_lines = 5;
85 static real default_real_one = 1.0;
86 static real default_real_zoom = 100.0;
87 static int default_int_w = 500;
88 static int default_int_h = 400;
89 static int default_undo_depth = 15;
90 static guint default_recent_documents = 5;
91 static Color default_colour = DEFAULT_GRID_COLOR;
92 static Color pbreak_colour = DEFAULT_PAGEBREAK_COLOR;
93 static guint default_dtree_dia_sort = DIA_TREE_SORT_INSERT;
94 static guint default_dtree_obj_sort = DIA_TREE_SORT_INSERT;
95 static const gchar *default_paper_name = NULL;
96 static const gchar *default_length_unit = "Centimeter";
97 static const gchar *default_fontsize_unit = "Point";
98 
99 static const char *default_favored_filter = N_("any");
100 
101 struct DiaPrefsTab {
102   char *title;
103   GtkTable *table;
104   int row;
105 };
106 
107 typedef enum {
108   UI_TAB,
109   DIA_TAB,
110   VIEW_TAB,
111   FAVOR_TAB,
112   GRID_TAB,
113   TREE_TAB
114 } TabIndex;
115 
116 struct DiaPrefsTab prefs_tabs[] =
117 {
118   {N_("User Interface"), NULL, 0},
119   {N_("Diagram Defaults"), NULL, 0},
120   {N_("View Defaults"), NULL, 0},
121   {N_("Favorites"), NULL, 0},
122   {N_("Grid Lines"), NULL, 0},
123   {N_("Diagram Tree"), NULL, 0},
124 };
125 
126 #define NUM_PREFS_TABS (sizeof(prefs_tabs)/sizeof(struct DiaPrefsTab))
127 
128 static GList *
_get_units_name_list(DiaPrefData * pref)129 _get_units_name_list(DiaPrefData *pref)
130 {
131   g_return_val_if_fail(pref->key == NULL, NULL);
132   return get_units_name_list();
133 }
134 static GList *
_get_paper_name_list(DiaPrefData * pref)135 _get_paper_name_list(DiaPrefData *pref)
136 {
137   g_return_val_if_fail(pref->key == NULL, NULL);
138   return get_paper_name_list();
139 }
140 static GList *
get_exporter_names(DiaPrefData * pref)141 get_exporter_names (DiaPrefData *pref)
142 {
143   GList *list = filter_get_unique_export_names(pref->key);
144   list = g_list_prepend (list, N_("any"));
145   return list;
146 }
147 
148 static void
set_favored_exporter(DiaPrefData * pref,gpointer ptr)149 set_favored_exporter (DiaPrefData *pref, gpointer ptr)
150 {
151   char *val = *((gchar **)ptr);
152   filter_set_favored_export(pref->key, val);
153 }
154 
155 /* retrive a structure offset */
156 #ifdef offsetof
157 #define PREF_OFFSET(field)        ((int) offsetof (struct DiaPreferences, field))
158 #else /* !offsetof */
159 #define PREF_OFFSET(field)        ((int) ((char*) &((struct DiaPreferences *) 0)->field))
160 #endif /* !offsetof */
161 
162 DiaPrefData prefs_data[] =
163 {
164   { "reset_tools_after_create", PREF_BOOLEAN, PREF_OFFSET(reset_tools_after_create),
165     &default_true, UI_TAB, N_("Reset tools after create") },
166 
167   { "undo_depth",               PREF_UINT,    PREF_OFFSET(undo_depth),
168     &default_undo_depth, UI_TAB, N_("Number of undo levels:") },
169 
170   { "reverse_rubberbanding_intersects", PREF_BOOLEAN, PREF_OFFSET(reverse_rubberbanding_intersects),
171     &default_true, UI_TAB, N_("Reverse dragging selects\nintersecting objects") },
172 
173   { "recent_documents_list_size", PREF_UINT, PREF_OFFSET(recent_documents_list_size),
174     &default_recent_documents, 0, N_("Recent documents list size:") },
175 
176   { "use_menu_bar", PREF_BOOLEAN, PREF_OFFSET(new_view.use_menu_bar),
177     &default_true, UI_TAB, N_("Use menu bar") },
178 
179   { "toolbox_on_top", PREF_BOOLEAN, PREF_OFFSET(toolbox_on_top),
180     &default_false, UI_TAB, N_("Keep tool box on top of diagram windows"),
181     NULL, FALSE, NULL, update_floating_toolbox},
182   { "length_unit", PREF_CHOICE, PREF_OFFSET(length_unit),
183     &default_length_unit, UI_TAB, N_("Length unit:"), NULL, FALSE,
184     _get_units_name_list, update_internal_prefs },
185   { "fontsize_unit", PREF_CHOICE, PREF_OFFSET(fontsize_unit),
186     &default_fontsize_unit, UI_TAB, N_("Font-size unit:"), NULL, FALSE,
187     _get_units_name_list, update_internal_prefs },
188 
189   { NULL, PREF_NONE, 0, NULL, DIA_TAB, N_("New diagram:") },
190   { "is_portrait", PREF_BOOLEAN, PREF_OFFSET(new_diagram.is_portrait), &default_true, DIA_TAB, N_("Portrait") },
191   { "new_diagram_papertype", PREF_CHOICE, PREF_OFFSET(new_diagram.papertype),
192     &default_paper_name, DIA_TAB, N_("Paper type:"), NULL, FALSE, _get_paper_name_list },
193   { "new_diagram_bgcolour", PREF_COLOUR, PREF_OFFSET(new_diagram.bg_color),
194     &color_white, DIA_TAB, N_("Background Color:") },
195   { "compress_save",            PREF_BOOLEAN, PREF_OFFSET(new_diagram.compress_save),
196     &default_true, DIA_TAB, N_("Compress saved files") },
197   { NULL, PREF_END_GROUP, 0, NULL, DIA_TAB, NULL },
198 
199   { NULL, PREF_NONE, 0, NULL, DIA_TAB, N_("Connection Points:") },
200   { "show_cx_pts", PREF_BOOLEAN, PREF_OFFSET(show_cx_pts), &default_true, DIA_TAB, N_("Visible") },
201   { "snap_object", PREF_BOOLEAN, PREF_OFFSET(snap_object), &default_true, DIA_TAB, N_("Snap to object") },
202   { NULL, PREF_END_GROUP, 0, NULL, DIA_TAB, NULL },
203 
204   { NULL, PREF_NONE, 0, NULL, VIEW_TAB, N_("New window:") },
205   { "new_view_width", PREF_UINT, PREF_OFFSET(new_view.width), &default_int_w, VIEW_TAB, N_("Width:") },
206   { "new_view_height", PREF_UINT, PREF_OFFSET(new_view.height), &default_int_h, VIEW_TAB, N_("Height:") },
207   { "new_view_zoom", PREF_UREAL, PREF_OFFSET(new_view.zoom), &default_real_zoom, VIEW_TAB, N_("Magnify:") },
208   { NULL, PREF_END_GROUP, 0, NULL, 1, NULL },
209 
210   { NULL, PREF_NONE, 0, NULL, VIEW_TAB, N_("Page breaks:") },
211   { "pagebreak_visible", PREF_BOOLEAN, PREF_OFFSET(pagebreak.visible), &default_true, VIEW_TAB, N_("Visible") },
212   { "pagebreak_colour", PREF_COLOUR, PREF_OFFSET(new_diagram.pagebreak_color), &pbreak_colour, VIEW_TAB, N_("Color:") },
213   { "pagebreak_solid", PREF_BOOLEAN, PREF_OFFSET(pagebreak.solid), &default_true, VIEW_TAB, N_("Solid lines") },
214   { NULL, PREF_END_GROUP, 0, NULL, VIEW_TAB, NULL },
215 
216   { NULL, PREF_NONE, 0, NULL, VIEW_TAB, N_("Antialias:") },
217   { "view_antialised", PREF_BOOLEAN, PREF_OFFSET(view_antialised), &default_false, VIEW_TAB, N_("view antialised") },
218   { NULL, PREF_END_GROUP, 0, NULL, VIEW_TAB, NULL },
219 
220   /* Favored Filter */
221   { NULL, PREF_NONE, 0, NULL, FAVOR_TAB, N_("Export") },
222   { "favored_png_export", PREF_CHOICE, PREF_OFFSET(favored_filter.png), &default_favored_filter,
223     FAVOR_TAB, N_("Portable Network Graphics"), NULL, FALSE, get_exporter_names, set_favored_exporter, "PNG" },
224   { "favored_svg_export", PREF_CHOICE, PREF_OFFSET(favored_filter.svg), &default_favored_filter,
225     FAVOR_TAB, N_("Scalable Vector Graphics"), NULL, FALSE, get_exporter_names, set_favored_exporter, "SVG" },
226   { "favored_ps_export", PREF_CHOICE, PREF_OFFSET(favored_filter.ps), &default_favored_filter,
227     FAVOR_TAB, N_("PostScript"), NULL, FALSE, get_exporter_names, set_favored_exporter, "PS" },
228   { "favored_wmf_export", PREF_CHOICE, PREF_OFFSET(favored_filter.wmf), &default_favored_filter,
229     FAVOR_TAB, N_("Windows MetaFile"), NULL, FALSE, get_exporter_names, set_favored_exporter, "WMF" },
230   { "favored_emf_export", PREF_CHOICE, PREF_OFFSET(favored_filter.emf), &default_favored_filter,
231     FAVOR_TAB, N_("Enhanced MetaFile"), NULL, FALSE, get_exporter_names, set_favored_exporter, "EMF" },
232   { NULL, PREF_END_GROUP, 0, NULL, FAVOR_TAB, NULL },
233 
234   /*{ NULL, PREF_NONE, 0, NULL, 3, N_("Grid:") }, */
235   { "grid_visible", PREF_BOOLEAN, PREF_OFFSET(grid.visible), &default_true, GRID_TAB, N_("Visible") },
236   { "grid_snap", PREF_BOOLEAN, PREF_OFFSET(grid.snap), &default_false, GRID_TAB, N_("Snap to") },
237   { "grid_dynamic", PREF_BOOLEAN, PREF_OFFSET(grid.dynamic), &default_true, GRID_TAB, N_("Dynamic grid resizing") },
238   { "grid_x", PREF_UREAL, PREF_OFFSET(grid.x), &default_real_one, GRID_TAB, N_("X Size:") },
239   { "grid_y", PREF_UREAL, PREF_OFFSET(grid.y), &default_real_one, GRID_TAB, N_("Y Size:") },
240   { "grid_colour", PREF_COLOUR, PREF_OFFSET(new_diagram.grid_color), &default_colour, GRID_TAB, N_("Color:") },
241   { "grid_major", PREF_UINT, PREF_OFFSET(grid.major_lines), &default_major_lines, GRID_TAB, N_("Lines per major line") },
242   { "grid_hex", PREF_BOOLEAN, PREF_OFFSET(grid.hex), &default_false, GRID_TAB, N_("Hex grid") },
243   { "grid_w", PREF_UREAL, PREF_OFFSET(grid.w), &default_real_one, GRID_TAB, N_("Hex Size:") },
244   /*  { "grid_solid", PREF_BOOLEAN, PREF_OFFSET(grid.solid), &default_true, 3, N_("Solid lines:") },  */
245 
246   { "render_bounding_boxes", PREF_BOOLEAN,PREF_OFFSET(render_bounding_boxes),
247     &default_false,0,"render bounding boxes",NULL, TRUE},
248 
249   /* There's really no reason to not pretty format it, and allowing non-pretty
250      can lead to problems with long lines, CVS etc.
251   { "pretty_formated_xml", PREF_BOOLEAN,PREF_OFFSET(pretty_formated_xml),
252     &default_true,0,"pretty formated xml",NULL, TRUE},
253   */
254 
255   { NULL, PREF_NONE, 0, NULL, TREE_TAB, N_("Diagram tree window:") },
256   { "diagram_tree_save_hidden", PREF_BOOLEAN, PREF_OFFSET(dia_tree.save_hidden),
257     &default_false, TREE_TAB, N_("Save hidden object types")},
258   { "diagram_tree_dia_sort", PREF_UINT, PREF_OFFSET(dia_tree.dia_sort),
259     &default_dtree_dia_sort, TREE_TAB, "default diagram sort order", NULL, TRUE},
260   { "diagram_tree_obj_sort", PREF_UINT, PREF_OFFSET(dia_tree.obj_sort),
261     &default_dtree_obj_sort, TREE_TAB, "default object sort order", NULL, TRUE},
262   { NULL, PREF_END_GROUP, 0, NULL, TREE_TAB, NULL },
263 };
264 
265 #define NUM_PREFS_DATA (sizeof(prefs_data)/sizeof(DiaPrefData))
266 
267 static void prefs_create_dialog(void);
268 static void prefs_set_value_in_widget(GtkWidget * widget, DiaPrefData *data,  gpointer ptr);
269 static void prefs_get_value_from_widget(GtkWidget * widget, DiaPrefData *data, gpointer ptr);
270 static void prefs_update_dialog_from_prefs(void);
271 static void prefs_update_prefs_from_dialog(void);
272 /* static gint prefs_apply(GtkWidget *widget, gpointer data); */
273 
274 
275 static GtkWidget *prefs_dialog = NULL;
276 
277 void
prefs_show(void)278 prefs_show(void)
279 {
280   prefs_create_dialog();
281   gtk_widget_show(prefs_dialog);
282 
283   prefs_update_dialog_from_prefs();
284 }
285 
286 void
prefs_set_defaults(void)287 prefs_set_defaults(void)
288 {
289   int i;
290   gpointer ptr;
291 
292   /* Since we can't call this in static initialization, we have to
293    * do it here.
294    */
295   if (default_paper_name == NULL)
296     default_paper_name = get_paper_name(get_default_paper());
297 
298   for (i=0;i<NUM_PREFS_DATA;i++) {
299     ptr = (char *)&prefs + prefs_data[i].offset;
300 
301     switch (prefs_data[i].type) {
302     case PREF_BOOLEAN:
303       *(int *)ptr = *(int *)prefs_data[i].default_value;
304       *(int *)ptr = persistence_register_boolean(prefs_data[i].name, *(int *)ptr);
305       break;
306     case PREF_INT:
307     case PREF_UINT:
308       *(int *)ptr = *(int *)prefs_data[i].default_value;
309       *(int *)ptr = persistence_register_integer(prefs_data[i].name, *(int *)ptr);
310       break;
311     case PREF_REAL:
312     case PREF_UREAL:
313       *(real *)ptr = *(real *)prefs_data[i].default_value;
314       *(real *)ptr = persistence_register_real(prefs_data[i].name, *(real *)ptr);
315       break;
316     case PREF_COLOUR:
317       *(Color *)ptr = *(Color *)prefs_data[i].default_value;
318       *(Color *)ptr = *persistence_register_color(prefs_data[i].name, (Color *)ptr);
319       break;
320     case PREF_CHOICE:
321     case PREF_STRING:
322       *(gchar **)ptr = *(gchar **)prefs_data[i].default_value;
323       *(gchar **)ptr = persistence_register_string(prefs_data[i].name, *(gchar **)ptr);
324       break;
325     case PREF_NONE:
326     case PREF_END_GROUP:
327       break;
328     }
329     /* set initial preferences, but dont talk about restarting */
330     if (prefs_data[i].update_function)
331       (prefs_data[i].update_function)(&prefs_data[i], ptr);
332   }
333   update_internal_prefs(&prefs_data[i], NULL);
334 }
335 
336 void
prefs_save(void)337 prefs_save(void)
338 {
339   int i;
340   gpointer ptr;
341   for (i=0;i<NUM_PREFS_DATA;i++) {
342     if ((prefs_data[i].type == PREF_NONE) || (prefs_data[i].type == PREF_END_GROUP))
343       continue;
344 
345     ptr = (char *)&prefs + prefs_data[i].offset;
346 
347     switch (prefs_data[i].type) {
348     case PREF_BOOLEAN:
349       persistence_set_boolean(prefs_data[i].name, *(gint *)ptr);
350       break;
351     case PREF_INT:
352     case PREF_UINT:
353       persistence_set_integer(prefs_data[i].name, *(gint *)ptr);
354       break;
355     case PREF_REAL:
356     case PREF_UREAL:
357 
358       persistence_set_real(prefs_data[i].name, *(real *)ptr);
359       break;
360     case PREF_COLOUR:
361       persistence_set_color(prefs_data[i].name, (Color *)ptr);
362       break;
363     case PREF_CHOICE:
364     case PREF_STRING:
365       persistence_set_string(prefs_data[i].name, *(gchar **)ptr);
366       break;
367     case PREF_NONE:
368     case PREF_END_GROUP:
369       break;
370     }
371   }
372 }
373 
374 
375 
376 void
prefs_init(void)377 prefs_init(void)
378 {
379   prefs_set_defaults();
380 
381   render_bounding_boxes = prefs.render_bounding_boxes;
382 }
383 
384 static void
prefs_set_value_in_widget(GtkWidget * widget,DiaPrefData * data,gpointer ptr)385 prefs_set_value_in_widget(GtkWidget * widget, DiaPrefData *data,
386 			  gpointer ptr)
387 {
388   switch(data->type) {
389   case PREF_BOOLEAN:
390     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), *((int *)ptr));
391     break;
392   case PREF_INT:
393   case PREF_UINT:
394     gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget),
395 			      (gfloat) (*((int *)ptr)));
396     break;
397   case PREF_REAL:
398   case PREF_UREAL:
399     gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget),
400 			      (gfloat) (*((real *)ptr)));
401     break;
402   case PREF_COLOUR:
403     dia_color_selector_set_color(widget, (Color *)ptr);
404     break;
405   case PREF_CHOICE: {
406     GList *names = (data->choice_list_function)(data);
407     int index;
408     char *val = *((gchar**)ptr);
409     for (index = 0; names != NULL; names = g_list_next(names), index++) {
410       if (!val || !strcmp(val, (gchar *)names->data))
411 	break;
412     }
413     if (names == NULL) return;
414     gtk_combo_box_set_active (GTK_COMBO_BOX (widget), index);
415     break;
416   }
417   case PREF_STRING:
418     gtk_entry_set_text(GTK_ENTRY(widget), (gchar *)(*((gchar **)ptr)));
419     break;
420   case PREF_NONE:
421   case PREF_END_GROUP:
422     break;
423   }
424 }
425 
426 static void
prefs_get_value_from_widget(GtkWidget * widget,DiaPrefData * data,gpointer ptr)427 prefs_get_value_from_widget(GtkWidget * widget, DiaPrefData *data,
428 			    gpointer ptr)
429 {
430   gboolean changed = FALSE;
431   switch(data->type) {
432   case PREF_BOOLEAN: {
433       int prev = *((int *)ptr);
434       *((int *)ptr) = GTK_TOGGLE_BUTTON(widget)->active;
435       changed = (prev != *((int *)ptr));
436     }
437     break;
438   case PREF_INT:
439   case PREF_UINT: {
440       int prev = *((int *)ptr);
441       *((int *)ptr) = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
442       changed = (prev != *((int *)ptr));
443     }
444     break;
445   case PREF_REAL:
446   case PREF_UREAL: {
447       real prev = *((real *)ptr);
448       *((real *)ptr) = (real)
449         gtk_spin_button_get_value (GTK_SPIN_BUTTON(widget));
450       changed = (prev != *((real *)ptr));
451     }
452     break;
453   case PREF_COLOUR: {
454       Color prev = *(Color *)ptr;
455       dia_color_selector_get_color(widget, (Color *)ptr);
456       changed = memcmp (&prev, ptr, sizeof(Color));
457     }
458     break;
459   case PREF_CHOICE: {
460     int index = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
461     GList *names = (data->choice_list_function)(data);
462     *((gchar **)ptr) = g_strdup((gchar *)g_list_nth_data(names, index));
463     /* XXX changed */
464     changed = TRUE;
465     break;
466   }
467   case PREF_STRING:
468     *((gchar **)ptr) = (gchar *)gtk_entry_get_text(GTK_ENTRY(widget));
469     /* XXX changed */
470     changed = TRUE;
471     break;
472   case PREF_NONE:
473   case PREF_END_GROUP:
474     break;
475   }
476   if (changed && data->update_function != NULL) {
477     (data->update_function)(data, ptr);
478   }
479 }
480 
481 static void
prefs_boolean_toggle(GtkWidget * widget,gpointer data)482 prefs_boolean_toggle(GtkWidget *widget, gpointer data)
483 {
484   guint active = GTK_TOGGLE_BUTTON(widget)->active;
485   gtk_button_set_label(GTK_BUTTON(widget), active ? _("Yes") : _("No"));
486 }
487 
488 static GtkWidget *
prefs_get_property_widget(DiaPrefData * data)489 prefs_get_property_widget(DiaPrefData *data)
490 {
491   GtkWidget *widget = NULL;
492   GtkAdjustment *adj;
493 
494   switch(data->type) {
495   case PREF_BOOLEAN:
496     widget = gtk_toggle_button_new_with_label (_("No"));
497     g_signal_connect (GTK_OBJECT (widget), "toggled",
498 		      G_CALLBACK (prefs_boolean_toggle), NULL);
499     break;
500   case PREF_INT:
501     adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0,
502 					    G_MININT, G_MAXINT,
503 					    1.0, 10.0, 0));
504     widget = gtk_spin_button_new (adj, 1.0, 0);
505     gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), TRUE);
506     gtk_widget_set_size_request (widget, 80, -1);
507     break;
508   case PREF_UINT:
509     adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0,
510 					    0.0, G_MAXINT,
511 					    1.0, 10.0, 0));
512     widget = gtk_spin_button_new (adj, 1.0, 0);
513     gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), TRUE);
514     gtk_widget_set_size_request (widget, 80, -1);
515     break;
516   case PREF_REAL:
517     adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0,
518 					    G_MINFLOAT, G_MAXFLOAT,
519 					    1.0, 10.0, 0));
520     widget = gtk_spin_button_new (adj, 1.0, 3);
521     gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), TRUE);
522     gtk_widget_set_size_request (widget, 80, -1);
523     break;
524   case PREF_UREAL:
525     adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0,
526 					    0.0, G_MAXFLOAT,
527 					    1.0, 10.0, 0 ));
528     widget = gtk_spin_button_new (adj, 1.0, 3);
529     gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), TRUE);
530     gtk_widget_set_size_request (widget, 80, -1);
531     break;
532   case PREF_COLOUR:
533     widget = dia_color_selector_new();
534     break;
535   case PREF_STRING:
536     widget = gtk_entry_new();
537     break;
538   case PREF_CHOICE: {
539     GList *names;
540     widget = gtk_combo_box_new_text ();
541     for (names = (data->choice_list_function)(data);
542          names != NULL;
543 	 names = g_list_next(names)) {
544       gtk_combo_box_append_text (GTK_COMBO_BOX (widget), (gchar *)names->data);
545     }
546     break;
547   }
548   case PREF_NONE:
549   case PREF_END_GROUP:
550     widget = NULL;
551     break;
552   }
553   if (widget != NULL)
554     gtk_widget_show(widget);
555   return widget;
556 }
557 
558 static gint
prefs_respond(GtkWidget * widget,gint response_id,gpointer data)559 prefs_respond(GtkWidget *widget,
560                    gint       response_id,
561                    gpointer   data)
562 {
563   if (   response_id == GTK_RESPONSE_APPLY
564       || response_id == GTK_RESPONSE_OK) {
565     prefs_update_prefs_from_dialog();
566     prefs_save();
567     diagram_redraw_all();
568   }
569 
570   if (response_id != GTK_RESPONSE_APPLY)
571     gtk_widget_hide(widget);
572 
573   return 0;
574 }
575 
576 static void
prefs_create_dialog(void)577 prefs_create_dialog(void)
578 {
579   GtkWidget *label;
580   GtkWidget *dialog_vbox;
581   GtkWidget *notebook;
582   GtkTable *top_table = NULL; /* top level table for the tab */
583   GtkTable *current_table = NULL;
584   int i;
585   int tab_idx = -1;
586 
587   if (prefs_dialog != NULL)
588     return;
589 
590   prefs_dialog = gtk_dialog_new_with_buttons(
591 			_("Preferences"),
592 			GTK_WINDOW(interface_get_toolbox_shell()),
593 			GTK_DIALOG_DESTROY_WITH_PARENT,
594 			GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
595 			GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
596 			GTK_STOCK_OK, GTK_RESPONSE_OK,
597 			NULL);
598   gtk_dialog_set_default_response (GTK_DIALOG(prefs_dialog), GTK_RESPONSE_OK);
599   gtk_window_set_resizable (GTK_WINDOW (prefs_dialog), TRUE);
600 
601   dialog_vbox = GTK_DIALOG (prefs_dialog)->vbox;
602 
603   gtk_window_set_role (GTK_WINDOW (prefs_dialog), "preferences_window");
604 
605   g_signal_connect(G_OBJECT (prefs_dialog), "response",
606                    G_CALLBACK (prefs_respond), NULL);
607 
608   g_signal_connect (GTK_OBJECT (prefs_dialog), "delete_event",
609 		    G_CALLBACK(gtk_widget_hide), NULL);
610   g_signal_connect (GTK_OBJECT (prefs_dialog), "destroy",
611 		    G_CALLBACK(gtk_widget_destroyed), &prefs_dialog);
612 
613   notebook = gtk_notebook_new ();
614   gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
615   gtk_box_pack_start (GTK_BOX (dialog_vbox), notebook, TRUE, TRUE, 0);
616   gtk_container_set_border_width (GTK_CONTAINER (notebook), 2);
617   gtk_widget_show (notebook);
618 
619   for (i=0;i<NUM_PREFS_TABS;i++) {
620     GtkWidget *table;
621     GtkWidget *notebook_page;
622 
623     label = gtk_label_new(gettext(prefs_tabs[i].title));
624     gtk_widget_show(label);
625 
626     table = gtk_table_new (9, 2, FALSE);
627     prefs_tabs[i].table = GTK_TABLE(table);
628     gtk_widget_set_size_request(table, -1, -1);
629     gtk_widget_show(table);
630 
631 #ifdef SCROLLED_PAGES
632     notebook_page = gtk_scrolled_window_new (NULL, NULL);
633     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (notebook_page),
634 				    GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
635     gtk_widget_show(notebook_page);
636 #else
637     notebook_page = table;
638 #endif/* SCROLLED_PAGES */
639 
640     gtk_notebook_append_page(GTK_NOTEBOOK(notebook), notebook_page, label);
641 
642 #ifdef SCROLLED_PAGES
643     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(notebook_page),
644 					  table);
645     gtk_viewport_set_shadow_type(GTK_VIEWPORT(GTK_BIN(notebook_page)->child),
646 				 GTK_SHADOW_NONE);
647 #endif /* SCROLLED_PAGES */
648 
649   }
650   gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
651 
652   tab_idx = -1;
653   for (i=0;i<NUM_PREFS_DATA;i++) {
654     GtkWidget *widget = NULL;
655     int row;
656 
657     if (prefs_data[i].hidden)
658       continue;
659 
660     if (tab_idx != prefs_data[i].tab) {
661       tab_idx = prefs_data[i].tab;
662       top_table = prefs_tabs[prefs_data[i].tab].table;
663       current_table = top_table;
664     }
665     row = prefs_tabs[tab_idx].row++;
666     switch(prefs_data[i].type) {
667     case PREF_NONE:
668       widget = gtk_frame_new(gettext(prefs_data[i].label_text));
669       gtk_widget_show (widget);
670       gtk_table_attach (current_table, widget, 0, 2,
671 			row, row + 1,
672 			GTK_FILL | GTK_EXPAND, GTK_FILL, 1, 1);
673       current_table = GTK_TABLE(gtk_table_new (9, 2, FALSE));
674       gtk_container_add(GTK_CONTAINER(widget), GTK_WIDGET(current_table));
675       gtk_widget_show(GTK_WIDGET(current_table));
676       break;
677     case PREF_END_GROUP:
678       current_table = top_table;
679       break;
680     case PREF_BOOLEAN:
681       widget = gtk_check_button_new_with_label (gettext(prefs_data[i].label_text));
682       gtk_widget_show (widget);
683       gtk_table_attach (current_table, widget, 0, 2,
684 			row, row + 1,
685 			GTK_FILL | GTK_EXPAND, GTK_FILL, 1, 1);
686       break;
687     default:
688       label = gtk_label_new (gettext(prefs_data[i].label_text));
689       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.3);
690       gtk_widget_show (label);
691 
692       gtk_table_attach (current_table, label, 0, 1,
693 			row, row + 1,
694 			GTK_FILL | GTK_EXPAND, GTK_FILL, 1, 1);
695 
696       widget = prefs_get_property_widget(&prefs_data[i]);
697       if (widget != NULL) {
698 	gtk_table_attach (current_table, widget, 1, 2,
699 			  row, row + 1,
700 			  GTK_FILL, GTK_FILL, 1, 1);
701       }
702       break;
703     }
704     prefs_data[i].widget = widget;
705 
706   }
707 
708   gtk_widget_show (prefs_dialog);
709 }
710 
711 static void
prefs_update_prefs_from_dialog(void)712 prefs_update_prefs_from_dialog(void)
713 {
714   GtkWidget *widget;
715   int i;
716   gpointer ptr;
717 
718   for (i=0;i<NUM_PREFS_DATA;i++) {
719     if (prefs_data[i].hidden) continue;
720     widget = prefs_data[i].widget;
721     ptr = (char *)&prefs + prefs_data[i].offset;
722 
723     prefs_get_value_from_widget(widget, &prefs_data[i],  ptr);
724   }
725 }
726 
727 static void
prefs_update_dialog_from_prefs(void)728 prefs_update_dialog_from_prefs(void)
729 {
730   GtkWidget *widget;
731   int i;
732   gpointer ptr;
733 
734   for (i=0;i<NUM_PREFS_DATA;i++) {
735     if (prefs_data[i].hidden) continue;
736     widget = prefs_data[i].widget;
737     ptr = (char *)&prefs + prefs_data[i].offset;
738 
739     prefs_set_value_in_widget(widget, &prefs_data[i],  ptr);
740   }
741 }
742 
743 /** Updates certain preferences that are kept in lib.  Both args
744  *  are currently unused and may be null.
745  */
746 static void
update_internal_prefs(DiaPrefData * pref,gpointer ptr)747 update_internal_prefs(DiaPrefData *pref, gpointer ptr)
748 {
749   char *val = NULL;
750 
751   if (!ptr)
752     return;
753   val = *(char **)ptr;
754   if (prefs.length_unit)
755     prefs_set_length_unit(prefs.length_unit);
756   if (prefs.fontsize_unit)
757     prefs_set_fontsize_unit(prefs.fontsize_unit);
758 }
759 
760 static void
update_floating_toolbox(DiaPrefData * pref,gpointer ptr)761 update_floating_toolbox(DiaPrefData *pref, gpointer ptr)
762 {
763   g_return_if_fail (pref->key == NULL);
764 
765   if (!app_is_interactive())
766     return;
767 
768   if (prefs.toolbox_on_top) {
769     /* Go through all diagrams and set toolbox transient for all displays */
770     GList *diagrams;
771     for (diagrams = dia_open_diagrams(); diagrams != NULL;
772 	 diagrams = g_list_next(diagrams)) {
773       Diagram *diagram = (Diagram *)diagrams->data;
774       GSList *displays;
775       for (displays = diagram->displays; displays != NULL;
776 	   displays = g_slist_next(displays)) {
777 	DDisplay *ddisp = (DDisplay *)displays->data;
778 	gtk_window_set_transient_for(GTK_WINDOW(interface_get_toolbox_shell()),
779 				     GTK_WINDOW(ddisp->shell));
780       }
781     }
782   } else {
783     GtkWindow *shell = GTK_WINDOW(interface_get_toolbox_shell());
784     if (shell)
785       gtk_window_set_transient_for(shell, NULL);
786   }
787 }
788 
789