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