1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 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
19 #include <config.h>
20 #include <string.h>
21 #include "intl.h"
22 #undef GTK_DISABLE_DEPRECATED /* GtkOptionMenu, ... */
23 #include "widgets.h"
24 #include "units.h"
25 #include "message.h"
26 #include "dia_dirs.h"
27 #include "arrows.h"
28 #include "diaarrowchooser.h"
29 #include "dialinechooser.h"
30 #include "persistence.h"
31 #include "dia-lib-icons.h"
32
33 #include <stdlib.h>
34 #include <glib.h>
35 #include <gdk/gdk.h>
36 #include <gtk/gtk.h>
37 #include <pango/pango.h>
38 #include <stdio.h>
39 #include <time.h>
40 #include <gdk/gdkkeysyms.h>
41
42 /* hidden internals for two reasosn:
43 * - noone is supposed to mess with the internals
44 * - it uses deprecated stuff
45 */
46 struct _DiaDynamicMenu {
47 GtkOptionMenu parent;
48
49 GList *default_entries;
50
51 DDMCreateItemFunc create_func;
52 DDMCallbackFunc activate_func;
53 gpointer userdata;
54
55 GtkMenuItem *other_item;
56
57 gchar *persistent_name;
58 gint cols;
59
60 gchar *active;
61 /** For the list-based versions, these are the options */
62 GList *options;
63
64 };
65
66 struct _DiaDynamicMenuClass {
67 GtkOptionMenuClass parent_class;
68 };
69
70
71 /************* DiaSizeSelector: ***************/
72 /* A widget that selects two sizes, width and height, optionally keeping
73 * aspect ratio. When created, aspect ratio is locked, but the user can
74 * unlock it. The current users do not store aspect ratio, so we have
75 * to give a good default.
76 */
77 struct _DiaSizeSelector
78 {
79 GtkHBox hbox;
80 GtkSpinButton *width, *height;
81 GtkToggleButton *aspect_locked;
82 real ratio;
83 GtkAdjustment *last_adjusted;
84 };
85
86 struct _DiaSizeSelectorClass
87 {
88 GtkHBoxClass parent_class;
89 };
90
91 enum {
92 DSS_VALUE_CHANGED,
93 DSS_LAST_SIGNAL
94 };
95
96 static guint dss_signals[DSS_LAST_SIGNAL] = { 0 };
97
98 static void
dia_size_selector_unrealize(GtkWidget * widget)99 dia_size_selector_unrealize(GtkWidget *widget)
100 {
101 (* GTK_WIDGET_CLASS (gtk_type_class(gtk_hbox_get_type ()))->unrealize) (widget);
102 }
103
104 static void
dia_size_selector_class_init(DiaSizeSelectorClass * class)105 dia_size_selector_class_init (DiaSizeSelectorClass *class)
106 {
107 GtkObjectClass *object_class;
108 GtkWidgetClass *widget_class;
109
110 object_class = (GtkObjectClass*) class;
111 widget_class = (GtkWidgetClass*) class;
112 widget_class->unrealize = dia_size_selector_unrealize;
113
114 dss_signals[DSS_VALUE_CHANGED]
115 = g_signal_new("value-changed",
116 G_TYPE_FROM_CLASS(class),
117 G_SIGNAL_RUN_FIRST,
118 0, NULL, NULL,
119 g_cclosure_marshal_VOID__VOID,
120 G_TYPE_NONE, 0);
121 }
122
123 static void
dia_size_selector_adjust_width(DiaSizeSelector * ss)124 dia_size_selector_adjust_width(DiaSizeSelector *ss)
125 {
126 real height =
127 gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(ss->height));
128 if (fabs(ss->ratio) > 1e-6)
129 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ss->width), height*ss->ratio);
130 }
131
132 static void
dia_size_selector_adjust_height(DiaSizeSelector * ss)133 dia_size_selector_adjust_height(DiaSizeSelector *ss)
134 {
135 real width =
136 gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(ss->width));
137 if (fabs(ss->ratio) > 1e-6)
138 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ss->height), width/ss->ratio);
139 }
140
141 static void
dia_size_selector_ratio_callback(GtkAdjustment * limits,gpointer userdata)142 dia_size_selector_ratio_callback(GtkAdjustment *limits, gpointer userdata)
143 {
144 static gboolean in_progress = FALSE;
145 DiaSizeSelector *ss = DIA_SIZE_SELECTOR(userdata);
146
147 ss->last_adjusted = limits;
148
149 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ss->aspect_locked))
150 && ss->ratio != 0.0) {
151
152 if (in_progress)
153 return;
154 in_progress = TRUE;
155
156 if (limits == gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ss->width))) {
157 dia_size_selector_adjust_height(ss);
158 } else {
159 dia_size_selector_adjust_width(ss);
160 }
161
162 in_progress = FALSE;
163 }
164
165 g_signal_emit(ss, dss_signals[DSS_VALUE_CHANGED], 0);
166
167 }
168
169 /** Update the ratio of this DSS to be the ratio of width to height.
170 * If height is 0, ratio becomes 0.0.
171 */
172 static void
dia_size_selector_set_ratio(DiaSizeSelector * ss,real width,real height)173 dia_size_selector_set_ratio(DiaSizeSelector *ss, real width, real height)
174 {
175 if (height > 0.0)
176 ss->ratio = width/height;
177 else
178 ss->ratio = 0.0;
179 }
180
181 static void
dia_size_selector_lock_pressed(GtkWidget * widget,gpointer data)182 dia_size_selector_lock_pressed(GtkWidget *widget, gpointer data)
183 {
184 DiaSizeSelector *ss = DIA_SIZE_SELECTOR(data);
185
186 dia_size_selector_set_ratio(ss,
187 gtk_spin_button_get_value(GTK_SPIN_BUTTON(ss->width)),
188 gtk_spin_button_get_value(GTK_SPIN_BUTTON(ss->height)));
189 }
190
191 /* Possible args: Init width, init height, digits */
192
193 static void
dia_size_selector_init(DiaSizeSelector * ss)194 dia_size_selector_init (DiaSizeSelector *ss)
195 {
196 GtkAdjustment *adj;
197
198 ss->ratio = 0.0;
199 /* Here's where we set up the real thing */
200 adj = GTK_ADJUSTMENT(gtk_adjustment_new(1.0, 0.01, 10,
201 0.1, 1.0, 0));
202 ss->width = GTK_SPIN_BUTTON(gtk_spin_button_new(adj, 1.0, 2));
203 gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(ss->width), TRUE);
204 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(ss->width), TRUE);
205 gtk_box_pack_start(GTK_BOX(ss), GTK_WIDGET(ss->width), FALSE, TRUE, 0);
206 gtk_widget_show(GTK_WIDGET(ss->width));
207
208 adj = GTK_ADJUSTMENT(gtk_adjustment_new(1.0, 0.01, 10,
209 0.1, 1.0, 0));
210 ss->height = GTK_SPIN_BUTTON(gtk_spin_button_new(adj, 1.0, 2));
211 gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(ss->height), TRUE);
212 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(ss->height), TRUE);
213 gtk_box_pack_start(GTK_BOX(ss), GTK_WIDGET(ss->height), FALSE, TRUE, 0);
214 gtk_widget_show(GTK_WIDGET(ss->height));
215
216 /* Replace label with images */
217 /* should make sure they're both unallocated when the widget dies.
218 * That should happen in the "destroy" handler, where both should
219 * be unref'd */
220 ss->aspect_locked =
221 GTK_TOGGLE_BUTTON(dia_toggle_button_new_with_icons
222 (dia_unbroken_chain_icon,
223 dia_broken_chain_icon));
224
225 gtk_container_set_border_width(GTK_CONTAINER(ss->aspect_locked), 0);
226
227 gtk_box_pack_start(GTK_BOX(ss), GTK_WIDGET(ss->aspect_locked), FALSE, TRUE, 0);
228 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ss->aspect_locked), TRUE);
229 gtk_widget_show(GTK_WIDGET(ss->aspect_locked));
230
231 gtk_signal_connect (GTK_OBJECT (ss->aspect_locked), "clicked",
232 (GtkSignalFunc) dia_size_selector_lock_pressed,
233 ss);
234 /* Make sure that the aspect ratio stays the same */
235 g_signal_connect(GTK_OBJECT(gtk_spin_button_get_adjustment(ss->width)),
236 "value_changed",
237 G_CALLBACK(dia_size_selector_ratio_callback), (gpointer)ss);
238 g_signal_connect(GTK_OBJECT(gtk_spin_button_get_adjustment(ss->height)),
239 "value_changed",
240 G_CALLBACK(dia_size_selector_ratio_callback), (gpointer)ss);
241 }
242
243 GtkType
dia_size_selector_get_type(void)244 dia_size_selector_get_type (void)
245 {
246 static GtkType dss_type = 0;
247
248 if (!dss_type) {
249 static const GtkTypeInfo dss_info = {
250 "DiaSizeSelector",
251 sizeof (DiaSizeSelector),
252 sizeof (DiaSizeSelectorClass),
253 (GtkClassInitFunc) dia_size_selector_class_init,
254 (GtkObjectInitFunc) dia_size_selector_init,
255 NULL,
256 NULL,
257 (GtkClassInitFunc) NULL,
258 };
259
260 dss_type = gtk_type_unique (gtk_hbox_get_type (), &dss_info);
261
262 }
263
264 return dss_type;
265 }
266
267 GtkWidget *
dia_size_selector_new(real width,real height)268 dia_size_selector_new (real width, real height)
269 {
270 GtkWidget *wid;
271
272 wid = GTK_WIDGET ( gtk_type_new (dia_size_selector_get_type ()));
273 dia_size_selector_set_size(DIA_SIZE_SELECTOR(wid), width, height);
274 return wid;
275 }
276
277 void
dia_size_selector_set_size(DiaSizeSelector * ss,real width,real height)278 dia_size_selector_set_size(DiaSizeSelector *ss, real width, real height)
279 {
280 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ss->width), width);
281 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ss->height), height);
282 /*
283 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ss->aspect_locked),
284 fabs(width - height) < 0.000001);
285 */
286 dia_size_selector_set_ratio(ss, width, height);
287 }
288
289 void
dia_size_selector_set_locked(DiaSizeSelector * ss,gboolean locked)290 dia_size_selector_set_locked(DiaSizeSelector *ss, gboolean locked)
291 {
292 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ss->aspect_locked))
293 && locked) {
294 dia_size_selector_set_ratio(ss,
295 gtk_spin_button_get_value(GTK_SPIN_BUTTON(ss->width)),
296 gtk_spin_button_get_value(GTK_SPIN_BUTTON(ss->height)));
297 }
298 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ss->aspect_locked), locked);
299 }
300
301 gboolean
dia_size_selector_get_size(DiaSizeSelector * ss,real * width,real * height)302 dia_size_selector_get_size(DiaSizeSelector *ss, real *width, real *height)
303 {
304 *width = gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(ss->width));
305 *height = gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(ss->height));
306 return gtk_toggle_button_get_active(ss->aspect_locked);
307 }
308
309 /************* DiaFontSelector: ***************/
310
311 /* Should these structs be in widgets.h instead? :
312 * _no_ they should not, noone is supposed to mess with the internals, ever heard of information hiding?
313 */
314
315 struct _DiaFontSelector
316 {
317 GtkHBox hbox;
318
319 GtkOptionMenu *font_omenu;
320 GtkOptionMenu *style_omenu;
321 GtkMenu *style_menu;
322 };
323
324 struct _DiaFontSelectorClass
325 {
326 GtkHBoxClass parent_class;
327 };
328
329 enum {
330 DFONTSEL_VALUE_CHANGED,
331 DFONTSEL_LAST_SIGNAL
332 };
333
334 static guint dfontsel_signals[DFONTSEL_LAST_SIGNAL] = { 0 };
335
336
337 /* New and improved font selector: Contains the three standard fonts
338 * and an 'Other fonts...' entry that opens the font dialog. The fonts
339 * selected in the font dialog are persistently added to the menu.
340 *
341 * +----------------+
342 * | Sans |
343 * | Serif |
344 * | Monospace |
345 * | -------------- |
346 * | Bodini |
347 * | CurlyGothic |
348 * | OldWestern |
349 * | -------------- |
350 * | Other fonts... |
351 * +----------------+
352 */
353
354 static void dia_font_selector_fontmenu_callback(DiaDynamicMenu *ddm,
355 gpointer data);
356 static void dia_font_selector_stylemenu_callback(GtkMenu *menu,
357 gpointer data);
358 static void dia_font_selector_set_styles(DiaFontSelector *fs,
359 const gchar *name,
360 DiaFontStyle dia_style);
361 static void dia_font_selector_set_style_menu(DiaFontSelector *fs,
362 PangoFontFamily *pff,
363 DiaFontStyle dia_style);
364
365 static void
dia_font_selector_class_init(DiaFontSelectorClass * class)366 dia_font_selector_class_init (DiaFontSelectorClass *class)
367 {
368 GtkObjectClass *object_class;
369
370 object_class = (GtkObjectClass*) class;
371
372 dfontsel_signals[DFONTSEL_VALUE_CHANGED]
373 = g_signal_new("value_changed",
374 G_TYPE_FROM_CLASS(class),
375 G_SIGNAL_RUN_FIRST,
376 0, NULL, NULL,
377 g_cclosure_marshal_VOID__VOID,
378 G_TYPE_NONE, 0);
379 }
380
381 static int
dia_font_selector_sort_fonts(const void * p1,const void * p2)382 dia_font_selector_sort_fonts(const void *p1, const void *p2)
383 {
384 const gchar *n1 = pango_font_family_get_name(PANGO_FONT_FAMILY(*(void**)p1));
385 const gchar *n2 = pango_font_family_get_name(PANGO_FONT_FAMILY(*(void**)p2));
386 return g_ascii_strcasecmp(n1, n2);
387 }
388
389 static gchar*
replace_ampersands(gchar * string)390 replace_ampersands(gchar* string)
391 {
392 gchar** pieces = g_strsplit(string, "&", -1);
393 gchar* escaped = g_strjoinv("&", pieces);
394 g_strfreev(pieces);
395 return escaped;
396 }
397
398 static GtkWidget *
dia_font_selector_create_string_item(DiaDynamicMenu * ddm,gchar * string)399 dia_font_selector_create_string_item(DiaDynamicMenu *ddm, gchar *string)
400 {
401 GtkWidget *item = gtk_menu_item_new_with_label(string);
402 if (strchr(string, '&')) {
403 gchar *escaped = replace_ampersands(string);
404 gchar *label = g_strdup_printf("<span face=\"%s,sans\" size=\"medium\">%s</span>",
405 escaped, escaped);
406 gtk_label_set_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item))), label);
407 g_free(label);
408 g_free(escaped);
409 } else {
410 gchar *label = g_strdup_printf("<span face=\"%s,sans\" size=\"medium\">%s</span>",
411 string, string);
412 gtk_label_set_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item))), label);
413 g_free(label);
414 }
415 return item;
416 }
417
418 static void
dia_font_selector_init(DiaFontSelector * fs)419 dia_font_selector_init (DiaFontSelector *fs)
420 {
421 GtkWidget *menu;
422 GtkWidget *omenu;
423
424 PangoFontFamily **families;
425 int n_families,i;
426 GList *fontnames = NULL;
427
428 pango_context_list_families (dia_font_get_context(),
429 &families, &n_families);
430 qsort(families, n_families, sizeof(PangoFontFamily*),
431 dia_font_selector_sort_fonts);
432 /* Doing it the slow way until I find a better way */
433 for (i = 0; i < n_families; i++) {
434 fontnames = g_list_append(fontnames,
435 g_strdup(pango_font_family_get_name(families[i])));
436 }
437 g_free (families);
438
439 fs->font_omenu =
440 GTK_OPTION_MENU(dia_dynamic_menu_new_listbased(dia_font_selector_create_string_item,
441 fs, _("Other fonts"),
442 fontnames, "font-menu"));
443 g_signal_connect(DIA_DYNAMIC_MENU(fs->font_omenu), "value-changed",
444 G_CALLBACK(dia_font_selector_fontmenu_callback), fs);
445 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(fs->font_omenu),
446 "sans");
447 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(fs->font_omenu),
448 "serif");
449 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(fs->font_omenu),
450 "monospace");
451 gtk_widget_show(GTK_WIDGET(fs->font_omenu));
452
453 /* Now build the style menu button */
454 omenu = gtk_option_menu_new();
455 fs->style_omenu = GTK_OPTION_MENU(omenu);
456 menu = gtk_menu_new ();
457 /* No callback needed since fs->style_menu keeps getting replaced. */
458 fs->style_menu = GTK_MENU(menu);
459 gtk_option_menu_set_menu (GTK_OPTION_MENU (fs->style_omenu), menu);
460
461 gtk_widget_show(menu);
462 gtk_widget_show(omenu);
463
464 gtk_box_pack_start_defaults(GTK_BOX(fs), GTK_WIDGET(fs->font_omenu));
465 gtk_box_pack_start_defaults(GTK_BOX(fs), GTK_WIDGET(fs->style_omenu));
466 }
467
468 GtkType
dia_font_selector_get_type(void)469 dia_font_selector_get_type (void)
470 {
471 static GtkType dfs_type = 0;
472
473 if (!dfs_type) {
474 static const GtkTypeInfo dfs_info = {
475 "DiaFontSelector",
476 sizeof (DiaFontSelector),
477 sizeof (DiaFontSelectorClass),
478 (GtkClassInitFunc) dia_font_selector_class_init,
479 (GtkObjectInitFunc) dia_font_selector_init,
480 NULL,
481 NULL,
482 (GtkClassInitFunc) NULL
483 };
484
485 dfs_type = gtk_type_unique (gtk_hbox_get_type (), &dfs_info);
486 }
487
488 return dfs_type;
489 }
490
491 GtkWidget *
dia_font_selector_new()492 dia_font_selector_new ()
493 {
494 return GTK_WIDGET ( gtk_type_new (dia_font_selector_get_type ()));
495 }
496
497 static PangoFontFamily *
dia_font_selector_get_family_from_name(GtkWidget * widget,const gchar * fontname)498 dia_font_selector_get_family_from_name(GtkWidget *widget, const gchar *fontname)
499 {
500 PangoFontFamily **families;
501 int n_families,i;
502
503 pango_context_list_families (dia_font_get_context(),
504 &families, &n_families);
505 /* Doing it the slow way until I find a better way */
506 for (i = 0; i < n_families; i++) {
507 if (!(g_ascii_strcasecmp(pango_font_family_get_name(families[i]), fontname))) {
508 PangoFontFamily *fam = families[i];
509 g_free(families);
510 return fam;
511 }
512 }
513 g_warning(_("Couldn't find font family for %s\n"), fontname);
514 g_free(families);
515 return NULL;
516 }
517
518 static void
dia_font_selector_fontmenu_callback(DiaDynamicMenu * ddm,gpointer data)519 dia_font_selector_fontmenu_callback(DiaDynamicMenu *ddm, gpointer data)
520 {
521 DiaFontSelector *fs = DIAFONTSELECTOR(data);
522 char *fontname = dia_dynamic_menu_get_entry(ddm);
523 dia_font_selector_set_styles(fs, fontname, -1);
524 g_signal_emit(GTK_OBJECT(fs),
525 dfontsel_signals[DFONTSEL_VALUE_CHANGED], 0);
526 g_free(fontname);
527 }
528
529 static void
dia_font_selector_stylemenu_callback(GtkMenu * menu,gpointer data)530 dia_font_selector_stylemenu_callback(GtkMenu *menu, gpointer data)
531 {
532 DiaFontSelector *fs = DIAFONTSELECTOR(data);
533 g_signal_emit(GTK_OBJECT(fs),
534 dfontsel_signals[DFONTSEL_VALUE_CHANGED], 0);
535 }
536
537 static char *style_labels[] = {
538 "Normal",
539 "Oblique",
540 "Italic",
541 "Ultralight",
542 "Ultralight-Oblique",
543 "Ultralight-Italic",
544 "Light",
545 "Light-Oblique",
546 "Light-Italic",
547 "Medium",
548 "Medium-Oblique",
549 "Medium-Italic",
550 "Demibold",
551 "Demibold-Oblique",
552 "Demibold-Italic",
553 "Bold",
554 "Bold-Oblique",
555 "Bold-Italic",
556 "Ultrabold",
557 "Ultrabold-Oblique",
558 "Ultrabold-Italic",
559 "Heavy",
560 "Heavy-Oblique",
561 "Heavy-Italic"
562 };
563
564 static void
dia_font_selector_set_style_menu(DiaFontSelector * fs,PangoFontFamily * pff,DiaFontStyle dia_style)565 dia_font_selector_set_style_menu(DiaFontSelector *fs,
566 PangoFontFamily *pff,
567 DiaFontStyle dia_style)
568 {
569 int select = 0;
570 PangoFontFace **faces = NULL;
571 guint nfaces = 0;
572 guint i=0;
573 GtkWidget *menu = NULL;
574 long stylebits = 0;
575 int menu_item_nr = 0;
576 GSList *group = NULL;
577
578 menu = gtk_menu_new ();
579 g_signal_connect(menu, "selection-done",
580 G_CALLBACK(dia_font_selector_stylemenu_callback), fs);
581
582 pango_font_family_list_faces(pff, &faces, &nfaces);
583
584 for (i = 0; i < nfaces; i++) {
585 PangoFontDescription *pfd = pango_font_face_describe(faces[i]);
586 PangoStyle style = pango_font_description_get_style(pfd);
587 PangoWeight weight = pango_font_description_get_weight(pfd);
588 /**
589 * This is a quick and dirty way to pick the styles present,
590 * sort them and avoid duplicates.
591 * We set a bit for each style present, bit (weight*3+style)
592 * From style_labels, we pick #(weight*3+style)
593 * where weight and style are the Dia types.
594 */
595 /* Account for DIA_WEIGHT_NORMAL hack */
596 int weightnr = (weight-200)/100;
597 if (weightnr < 2) weightnr ++;
598 else if (weightnr == 2) weightnr = 0;
599 stylebits |= 1 << (3*weightnr + style);
600 pango_font_description_free(pfd);
601 }
602
603 g_free(faces);
604
605 if (stylebits == 0) {
606 g_warning ("'%s' has no style!",
607 pango_font_family_get_name (pff) ? pango_font_family_get_name (pff) : "(null font)");
608 }
609
610 for (i = DIA_FONT_NORMAL; i <= (DIA_FONT_HEAVY | DIA_FONT_ITALIC); i+=4) {
611 GtkWidget *menuitem;
612 /**
613 * bad hack continued ...
614 */
615 int weight = DIA_FONT_STYLE_GET_WEIGHT(i) >> 4;
616 int slant = DIA_FONT_STYLE_GET_SLANT(i) >> 2;
617 if (DIA_FONT_STYLE_GET_SLANT(i) > DIA_FONT_ITALIC) continue;
618 if (!(stylebits & (1 << (3*weight + slant)))) continue;
619 menuitem = gtk_radio_menu_item_new_with_label (group, style_labels[3*weight+slant]);
620 group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menuitem));
621 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(i));
622 if (dia_style == i) {
623 select = menu_item_nr;
624 }
625 menu_item_nr++;
626 gtk_menu_append (GTK_MENU (menu), menuitem);
627 gtk_widget_show (menuitem);
628 }
629 gtk_widget_show(menu);
630 gtk_option_menu_remove_menu(fs->style_omenu);
631 gtk_option_menu_set_menu(fs->style_omenu, menu);
632 fs->style_menu = GTK_MENU(menu);
633 gtk_option_menu_set_history(GTK_OPTION_MENU(fs->style_omenu), select);
634 gtk_menu_set_active(fs->style_menu, select);
635 gtk_widget_set_sensitive(GTK_WIDGET(fs->style_omenu), menu_item_nr > 1);
636 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_menu_get_active(fs->style_menu)), TRUE);
637 }
638
639 static void
dia_font_selector_set_styles(DiaFontSelector * fs,const gchar * name,DiaFontStyle dia_style)640 dia_font_selector_set_styles(DiaFontSelector *fs,
641 const gchar *name, DiaFontStyle dia_style)
642 {
643 PangoFontFamily *pff;
644 pff = dia_font_selector_get_family_from_name(GTK_WIDGET(fs), name);
645 dia_font_selector_set_style_menu(fs, pff, dia_style);
646 }
647
648
649 /* API functions */
650 /** Set a string to be used for preview in the GTK font selector dialog.
651 * The start of this string will be copied.
652 * This function is now obsolete.
653 */
654 void
dia_font_selector_set_preview(DiaFontSelector * fs,gchar * text)655 dia_font_selector_set_preview(DiaFontSelector *fs, gchar *text) {
656 }
657
658 /** Set the current font to be shown in the font selector.
659 */
660 void
dia_font_selector_set_font(DiaFontSelector * fs,DiaFont * font)661 dia_font_selector_set_font(DiaFontSelector *fs, DiaFont *font)
662 {
663 const gchar *fontname = dia_font_get_family(font);
664 /* side effect: adds fontname to presistence list */
665 dia_dynamic_menu_select_entry(DIA_DYNAMIC_MENU(fs->font_omenu), fontname);
666 g_signal_emit(GTK_OBJECT(fs),
667 dfontsel_signals[DFONTSEL_VALUE_CHANGED], 0);
668 dia_font_selector_set_styles(fs, fontname, dia_font_get_style (font));
669 }
670
671 DiaFont *
dia_font_selector_get_font(DiaFontSelector * fs)672 dia_font_selector_get_font(DiaFontSelector *fs)
673 {
674 GtkWidget *menuitem;
675 char *fontname;
676 DiaFontStyle style;
677 DiaFont *font;
678
679 fontname = dia_dynamic_menu_get_entry(DIA_DYNAMIC_MENU(fs->font_omenu));
680 menuitem = gtk_menu_get_active(fs->style_menu);
681 if (!menuitem) /* FIXME: should not happen ??? (but does if we don't have added a style) */
682 style = 0;
683 else
684 style = GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(menuitem)));
685 font = dia_font_new(fontname, style, 1.0);
686 g_free(fontname);
687 return font;
688 }
689
690 /************* DiaAlignmentSelector: ***************/
691 struct _DiaAlignmentSelector
692 {
693 GtkOptionMenu omenu;
694
695 GtkMenu *alignment_menu;
696 };
697
698 struct _DiaAlignmentSelectorClass
699 {
700 GtkOptionMenuClass parent_class;
701 };
702
703 static void
dia_alignment_selector_class_init(DiaAlignmentSelectorClass * class)704 dia_alignment_selector_class_init (DiaAlignmentSelectorClass *class)
705 {
706 GtkObjectClass *object_class;
707
708 object_class = (GtkObjectClass*) class;
709 }
710
711 static void
dia_alignment_selector_init(DiaAlignmentSelector * fs)712 dia_alignment_selector_init (DiaAlignmentSelector *fs)
713 {
714 GtkWidget *menu;
715 GtkWidget *submenu;
716 GtkWidget *menuitem;
717 GSList *group;
718
719 menu = gtk_menu_new ();
720 fs->alignment_menu = GTK_MENU(menu);
721 submenu = NULL;
722 group = NULL;
723
724 menuitem = gtk_radio_menu_item_new_with_label (group, _("Left"));
725 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(ALIGN_LEFT));
726 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
727 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
728 gtk_widget_show (menuitem);
729
730 menuitem = gtk_radio_menu_item_new_with_label (group, _("Center"));
731 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(ALIGN_CENTER));
732 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
733 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
734 gtk_widget_show (menuitem);
735
736 menuitem = gtk_radio_menu_item_new_with_label (group, _("Right"));
737 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(ALIGN_RIGHT));
738 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
739 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
740 gtk_widget_show (menuitem);
741
742 gtk_menu_set_active(GTK_MENU (menu), DEFAULT_ALIGNMENT);
743 gtk_option_menu_set_menu (GTK_OPTION_MENU (fs), menu);
744 }
745
746 GtkType
dia_alignment_selector_get_type(void)747 dia_alignment_selector_get_type (void)
748 {
749 static GtkType dfs_type = 0;
750
751 if (!dfs_type) {
752 static const GtkTypeInfo dfs_info = {
753 "DiaAlignmentSelector",
754 sizeof (DiaAlignmentSelector),
755 sizeof (DiaAlignmentSelectorClass),
756 (GtkClassInitFunc) dia_alignment_selector_class_init,
757 (GtkObjectInitFunc) dia_alignment_selector_init,
758 NULL,
759 NULL,
760 (GtkClassInitFunc) NULL,
761 };
762
763 dfs_type = gtk_type_unique (gtk_option_menu_get_type (), &dfs_info);
764 }
765
766 return dfs_type;
767 }
768
769 GtkWidget *
dia_alignment_selector_new()770 dia_alignment_selector_new ()
771 {
772 return GTK_WIDGET ( gtk_type_new (dia_alignment_selector_get_type ()));
773 }
774
775
776 Alignment
dia_alignment_selector_get_alignment(DiaAlignmentSelector * fs)777 dia_alignment_selector_get_alignment(DiaAlignmentSelector *fs)
778 {
779 GtkWidget *menuitem;
780 void *align;
781
782 menuitem = gtk_menu_get_active(fs->alignment_menu);
783 align = gtk_object_get_user_data(GTK_OBJECT(menuitem));
784
785 return GPOINTER_TO_INT(align);
786 }
787
788 void
dia_alignment_selector_set_alignment(DiaAlignmentSelector * as,Alignment align)789 dia_alignment_selector_set_alignment (DiaAlignmentSelector *as,
790 Alignment align)
791 {
792 gtk_menu_set_active(GTK_MENU (as->alignment_menu), align);
793 gtk_option_menu_set_history (GTK_OPTION_MENU(as), align);
794 }
795
796 /************* DiaLineStyleSelector: ***************/
797 struct _DiaLineStyleSelector
798 {
799 GtkVBox vbox;
800
801 GtkOptionMenu *omenu;
802 GtkMenu *linestyle_menu;
803 GtkLabel *lengthlabel;
804 GtkSpinButton *dashlength;
805
806 };
807
808 struct _DiaLineStyleSelectorClass
809 {
810 GtkVBoxClass parent_class;
811 };
812
813 enum {
814 DLS_VALUE_CHANGED,
815 DLS_LAST_SIGNAL
816 };
817
818 static guint dls_signals[DLS_LAST_SIGNAL] = { 0 };
819
820 static void
dia_line_style_selector_class_init(DiaLineStyleSelectorClass * class)821 dia_line_style_selector_class_init (DiaLineStyleSelectorClass *class)
822 {
823 GtkObjectClass *object_class;
824
825 object_class = (GtkObjectClass*) class;
826
827 dls_signals[DLS_VALUE_CHANGED]
828 = g_signal_new("value-changed",
829 G_TYPE_FROM_CLASS(class),
830 G_SIGNAL_RUN_FIRST,
831 0, NULL, NULL,
832 g_cclosure_marshal_VOID__VOID,
833 G_TYPE_NONE, 0);
834 }
835
836 static void
set_linestyle_sensitivity(DiaLineStyleSelector * fs)837 set_linestyle_sensitivity(DiaLineStyleSelector *fs)
838 {
839 int state;
840 GtkWidget *menuitem;
841 if (!fs->linestyle_menu) return;
842 menuitem = gtk_menu_get_active(fs->linestyle_menu);
843 state = (GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(menuitem)))
844 != LINESTYLE_SOLID);
845
846 gtk_widget_set_sensitive(GTK_WIDGET(fs->lengthlabel), state);
847 gtk_widget_set_sensitive(GTK_WIDGET(fs->dashlength), state);
848 }
849
850 static void
linestyle_type_change_callback(GtkMenu * menu,gpointer data)851 linestyle_type_change_callback(GtkMenu *menu, gpointer data)
852 {
853 set_linestyle_sensitivity(DIALINESTYLESELECTOR(data));
854 g_signal_emit(DIALINESTYLESELECTOR(data),
855 dls_signals[DLS_VALUE_CHANGED], 0);
856 }
857
858 static void
linestyle_dashlength_change_callback(GtkSpinButton * sb,gpointer data)859 linestyle_dashlength_change_callback(GtkSpinButton *sb, gpointer data)
860 {
861 g_signal_emit(DIALINESTYLESELECTOR(data),
862 dls_signals[DLS_VALUE_CHANGED], 0);
863 }
864
865 static void
dia_line_style_selector_init(DiaLineStyleSelector * fs)866 dia_line_style_selector_init (DiaLineStyleSelector *fs)
867 {
868 GtkWidget *menu;
869 GtkWidget *submenu;
870 GtkWidget *menuitem, *ln;
871 GtkWidget *label;
872 GtkWidget *length;
873 GtkWidget *box;
874 GSList *group;
875 GtkAdjustment *adj;
876 gint i;
877
878 menu = gtk_option_menu_new();
879 fs->omenu = GTK_OPTION_MENU(menu);
880
881 menu = gtk_menu_new ();
882 fs->linestyle_menu = GTK_MENU(menu);
883 submenu = NULL;
884 group = NULL;
885
886 for (i = 0; i <= LINESTYLE_DOTTED; i++) {
887 menuitem = gtk_menu_item_new();
888 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(i));
889 ln = dia_line_preview_new(i);
890 gtk_container_add(GTK_CONTAINER(menuitem), ln);
891 gtk_widget_show(ln);
892 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
893 gtk_widget_show(menuitem);
894 }
895 #if 0
896 menuitem = gtk_radio_menu_item_new_with_label (group, _("Solid"));
897 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(LINESTYLE_SOLID));
898 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
899 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
900 gtk_widget_show (menuitem);
901
902 menuitem = gtk_radio_menu_item_new_with_label (group, _("Dashed"));
903 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(LINESTYLE_DASHED));
904 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
905 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
906 gtk_widget_show (menuitem);
907
908 menuitem = gtk_radio_menu_item_new_with_label (group, _("Dash-Dot"));
909 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(LINESTYLE_DASH_DOT));
910 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
911 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
912 gtk_widget_show (menuitem);
913
914 menuitem = gtk_radio_menu_item_new_with_label (group, _("Dash-Dot-Dot"));
915 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(LINESTYLE_DASH_DOT_DOT));
916 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
917 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
918 gtk_widget_show (menuitem);
919
920 menuitem = gtk_radio_menu_item_new_with_label (group, _("Dotted"));
921 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(LINESTYLE_DOTTED));
922 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
923 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
924 gtk_widget_show (menuitem);
925 #endif
926
927 gtk_menu_set_active(GTK_MENU (menu), DEFAULT_LINESTYLE);
928 gtk_option_menu_set_menu (GTK_OPTION_MENU (fs->omenu), menu);
929 g_signal_connect(GTK_OBJECT(menu), "selection-done",
930 G_CALLBACK(linestyle_type_change_callback), fs);
931
932 gtk_box_pack_start(GTK_BOX(fs), GTK_WIDGET(fs->omenu), FALSE, TRUE, 0);
933 gtk_widget_show(GTK_WIDGET(fs->omenu));
934
935 box = gtk_hbox_new(FALSE,0);
936 /* fs->sizebox = GTK_HBOX(box); */
937
938 label = gtk_label_new(_("Dash length: "));
939 fs->lengthlabel = GTK_LABEL(label);
940 gtk_box_pack_start_defaults(GTK_BOX(box), label);
941 gtk_widget_show(label);
942
943 adj = (GtkAdjustment *)gtk_adjustment_new(0.1, 0.00, 10.0, 0.1, 1.0, 0);
944 length = gtk_spin_button_new(adj, DEFAULT_LINESTYLE_DASHLEN, 2);
945 gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(length), TRUE);
946 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(length), TRUE);
947 fs->dashlength = GTK_SPIN_BUTTON(length);
948 gtk_box_pack_start_defaults(GTK_BOX (box), length);
949 gtk_widget_show (length);
950
951 g_signal_connect(GTK_OBJECT(length), "changed",
952 G_CALLBACK(linestyle_dashlength_change_callback), fs);
953
954 set_linestyle_sensitivity(fs);
955 gtk_box_pack_start_defaults(GTK_BOX(fs), box);
956 gtk_widget_show(box);
957
958 }
959
960 GtkType
dia_line_style_selector_get_type(void)961 dia_line_style_selector_get_type (void)
962 {
963 static GtkType dfs_type = 0;
964
965 if (!dfs_type) {
966 static const GtkTypeInfo dfs_info = {
967 "DiaLineStyleSelector",
968 sizeof (DiaLineStyleSelector),
969 sizeof (DiaLineStyleSelectorClass),
970 (GtkClassInitFunc) dia_line_style_selector_class_init,
971 (GtkObjectInitFunc) dia_line_style_selector_init,
972 NULL,
973 NULL,
974 (GtkClassInitFunc) NULL,
975 };
976
977 dfs_type = gtk_type_unique (gtk_vbox_get_type (), &dfs_info);
978 }
979
980 return dfs_type;
981 }
982
983 GtkWidget *
dia_line_style_selector_new()984 dia_line_style_selector_new ()
985 {
986 return GTK_WIDGET ( gtk_type_new (dia_line_style_selector_get_type ()));
987 }
988
989
990 void
dia_line_style_selector_get_linestyle(DiaLineStyleSelector * fs,LineStyle * ls,real * dl)991 dia_line_style_selector_get_linestyle(DiaLineStyleSelector *fs,
992 LineStyle *ls, real *dl)
993 {
994 GtkWidget *menuitem;
995 void *align;
996
997 menuitem = gtk_menu_get_active(fs->linestyle_menu);
998 align = gtk_object_get_user_data(GTK_OBJECT(menuitem));
999 *ls = GPOINTER_TO_INT(align);
1000 if (dl!=NULL) {
1001 *dl = gtk_spin_button_get_value(fs->dashlength);
1002 }
1003 }
1004
1005 void
dia_line_style_selector_set_linestyle(DiaLineStyleSelector * as,LineStyle linestyle,real dashlength)1006 dia_line_style_selector_set_linestyle (DiaLineStyleSelector *as,
1007 LineStyle linestyle, real dashlength)
1008 {
1009 gtk_menu_set_active(GTK_MENU (as->linestyle_menu), linestyle);
1010 gtk_option_menu_set_history (GTK_OPTION_MENU(as->omenu), linestyle);
1011 /* TODO restore this later */
1012 /* gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(gtk_menu_get_active(GTK_MENU(as->linestyle_menu))), TRUE);*/
1013 set_linestyle_sensitivity(DIALINESTYLESELECTOR(as));
1014 gtk_spin_button_set_value(GTK_SPIN_BUTTON(as->dashlength), dashlength);
1015 }
1016
1017
1018
1019 /************* DiaColorSelector: ***************/
1020
1021 static GtkWidget *
dia_color_selector_create_string_item(DiaDynamicMenu * ddm,gchar * string)1022 dia_color_selector_create_string_item(DiaDynamicMenu *ddm, gchar *string)
1023 {
1024 GtkWidget *item = gtk_menu_item_new_with_label(string);
1025 gint r, g, b;
1026 sscanf(string, "#%2x%2x%2x", &r, &g, &b);
1027
1028 /* See http://web.umr.edu/~rhall/commentary/color_readability.htm for
1029 * explanation of this formula */
1030 if (r*299+g*587+b*114 > 500 * 256) {
1031 gchar *label = g_strdup_printf("<span foreground=\"black\" background=\"%s\">%s</span>", string, string);
1032 gtk_label_set_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item))), label);
1033 g_free(label);
1034 } else {
1035 gchar *label = g_strdup_printf("<span foreground=\"white\" background=\"%s\">%s</span>", string, string);
1036 gtk_label_set_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item))), label);
1037 g_free(label);
1038 }
1039
1040 return item;
1041 }
1042
1043 static void
dia_color_selector_more_ok(GtkWidget * ok,gpointer userdata)1044 dia_color_selector_more_ok(GtkWidget *ok, gpointer userdata)
1045 {
1046 DiaDynamicMenu *ddm = g_object_get_data(G_OBJECT(userdata), "ddm");
1047 GtkWidget *colorsel = GTK_WIDGET(userdata);
1048 GdkColor gcol;
1049 gchar *entry;
1050
1051 gtk_color_selection_get_current_color(
1052 GTK_COLOR_SELECTION(
1053 GTK_COLOR_SELECTION_DIALOG(colorsel)->colorsel),
1054 &gcol);
1055
1056 entry = g_strdup_printf("#%02X%02X%02X", gcol.red/256, gcol.green/256, gcol.blue/256);
1057 dia_dynamic_menu_select_entry(ddm, entry);
1058 g_free(entry);
1059
1060 gtk_widget_destroy(colorsel);
1061 }
1062
1063 static void
dia_color_selector_more_callback(GtkWidget * widget,gpointer userdata)1064 dia_color_selector_more_callback(GtkWidget *widget, gpointer userdata)
1065 {
1066 GtkColorSelectionDialog *dialog = GTK_COLOR_SELECTION_DIALOG (gtk_color_selection_dialog_new(_("Select color")));
1067 DiaDynamicMenu *ddm = DIA_DYNAMIC_MENU(userdata);
1068 GtkColorSelection *colorsel = GTK_COLOR_SELECTION(dialog->colorsel);
1069 GString *palette = g_string_new ("");
1070
1071 gchar *old_color = dia_dynamic_menu_get_entry(ddm);
1072 /* Force history to the old place */
1073 dia_dynamic_menu_select_entry(ddm, old_color);
1074
1075 if (ddm->default_entries != NULL) {
1076 GList *tmplist;
1077 int index = 0;
1078 gboolean advance = TRUE;
1079
1080 for (tmplist = ddm->default_entries;
1081 tmplist != NULL || advance;
1082 tmplist = g_list_next(tmplist)) {
1083 const gchar* spec;
1084 GdkColor color;
1085
1086 /* handle both lists */
1087 if (!tmplist && advance) {
1088 advance = FALSE;
1089 tmplist = persistent_list_get_glist(ddm->persistent_name);
1090 if (!tmplist)
1091 break;
1092 }
1093 spec = (gchar *)tmplist->data;
1094
1095 gdk_color_parse (spec, &color);
1096 #if 0
1097 /* the easy way if the Gtk Team would decide to make it public */
1098 gtk_color_selection_set_palette_color (colorsel, index, &color);
1099 #else
1100 g_string_append (palette, spec);
1101 g_string_append (palette, ":");
1102 #endif
1103 if (0 == strcmp (spec, old_color)) {
1104 gtk_color_selection_set_previous_color (colorsel, &color);
1105 gtk_color_selection_set_current_color (colorsel, &color);
1106 }
1107 index++;
1108 }
1109 }
1110
1111 g_object_set (gtk_widget_get_settings (GTK_WIDGET (colorsel)), "gtk-color-palette", palette->str, NULL);
1112 gtk_color_selection_set_has_palette (colorsel, TRUE);
1113 g_string_free (palette, TRUE);
1114 g_free(old_color);
1115
1116 gtk_widget_hide(dialog->help_button);
1117
1118 gtk_signal_connect (GTK_OBJECT (dialog->ok_button), "clicked",
1119 (GtkSignalFunc) dia_color_selector_more_ok,
1120 dialog);
1121 gtk_signal_connect_object(GTK_OBJECT (dialog->cancel_button), "clicked",
1122 (GtkSignalFunc) gtk_widget_destroy,
1123 GTK_OBJECT(dialog));
1124 g_object_set_data(G_OBJECT(dialog), "ddm", ddm);
1125
1126 gtk_widget_show(GTK_WIDGET(dialog));
1127 }
1128
1129 GtkWidget *
dia_color_selector_new()1130 dia_color_selector_new ()
1131 {
1132 GtkWidget *otheritem = gtk_menu_item_new_with_label(_("More colors..."));
1133 GtkWidget *ddm = dia_dynamic_menu_new(dia_color_selector_create_string_item,
1134 NULL,
1135 GTK_MENU_ITEM(otheritem),
1136 "color-menu");
1137 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(ddm),
1138 "#000000");
1139 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(ddm),
1140 "#FFFFFF");
1141 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(ddm),
1142 "#FF0000");
1143 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(ddm),
1144 "#00FF00");
1145 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(ddm),
1146 "#0000FF");
1147 g_signal_connect(G_OBJECT(otheritem), "activate",
1148 G_CALLBACK(dia_color_selector_more_callback), ddm);
1149 gtk_widget_show(otheritem);
1150 return ddm;
1151 }
1152
1153
1154 void
dia_color_selector_get_color(GtkWidget * widget,Color * color)1155 dia_color_selector_get_color(GtkWidget *widget, Color *color)
1156 {
1157 gchar *entry = dia_dynamic_menu_get_entry(DIA_DYNAMIC_MENU(widget));
1158 gint r, g, b;
1159
1160 sscanf(entry, "#%2x%2x%2x", &r, &g, &b);
1161 g_free(entry);
1162 color->red = r / 255.0;
1163 color->green = g / 255.0;
1164 color->blue = b / 255.0;
1165 }
1166
1167 void
dia_color_selector_set_color(GtkWidget * widget,const Color * color)1168 dia_color_selector_set_color (GtkWidget *widget,
1169 const Color *color)
1170 {
1171 gint red, green, blue;
1172 gchar *entry;
1173 red = color->red * 255;
1174 green = color->green * 255;
1175 blue = color->blue * 255;
1176 if (color->red > 1.0 || color->green > 1.0 || color->blue > 1.0) {
1177 printf("Color out of range: r %f, g %f, b %f\n",
1178 color->red, color->green, color->blue);
1179 red = MIN(red, 255);
1180 green = MIN(green, 255);
1181 blue = MIN(blue, 255);
1182 }
1183 entry = g_strdup_printf("#%02X%02X%02X", red, green, blue);
1184 dia_dynamic_menu_select_entry(DIA_DYNAMIC_MENU(widget), entry);
1185 g_free (entry);
1186 }
1187
1188
1189 /************* DiaArrowSelector: ***************/
1190
1191 /* FIXME: Should these structs be in widgets.h instead? */
1192 struct _DiaArrowSelector
1193 {
1194 GtkVBox vbox;
1195
1196 GtkHBox *sizebox;
1197 GtkLabel *sizelabel;
1198 DiaSizeSelector *size;
1199
1200 GtkOptionMenu *omenu;
1201 };
1202
1203 struct _DiaArrowSelectorClass
1204 {
1205 GtkVBoxClass parent_class;
1206 };
1207
1208 enum {
1209 DAS_VALUE_CHANGED,
1210 DAS_LAST_SIGNAL
1211 };
1212
1213 static guint das_signals[DAS_LAST_SIGNAL] = {0};
1214
1215 static void
dia_arrow_selector_class_init(DiaArrowSelectorClass * class)1216 dia_arrow_selector_class_init (DiaArrowSelectorClass *class)
1217 {
1218 das_signals[DAS_VALUE_CHANGED]
1219 = g_signal_new("value_changed",
1220 G_TYPE_FROM_CLASS(class),
1221 G_SIGNAL_RUN_FIRST,
1222 0, NULL, NULL,
1223 g_cclosure_marshal_VOID__VOID,
1224 G_TYPE_NONE, 0);
1225 }
1226
1227 static void
set_size_sensitivity(DiaArrowSelector * as)1228 set_size_sensitivity(DiaArrowSelector *as)
1229 {
1230 int state;
1231 gchar *entryname = dia_dynamic_menu_get_entry(DIA_DYNAMIC_MENU(as->omenu));
1232
1233 state = (entryname != NULL) && (0 != g_ascii_strcasecmp(entryname, "None"));
1234 g_free(entryname);
1235
1236 gtk_widget_set_sensitive(GTK_WIDGET(as->sizelabel), state);
1237 gtk_widget_set_sensitive(GTK_WIDGET(as->size), state);
1238 }
1239
1240 static void
arrow_type_change_callback(DiaDynamicMenu * ddm,gpointer userdata)1241 arrow_type_change_callback(DiaDynamicMenu *ddm, gpointer userdata)
1242 {
1243 set_size_sensitivity(DIA_ARROW_SELECTOR(userdata));
1244 g_signal_emit(DIA_ARROW_SELECTOR(userdata),
1245 das_signals[DAS_VALUE_CHANGED], 0);
1246 }
1247
1248 static void
arrow_size_change_callback(DiaSizeSelector * size,gpointer userdata)1249 arrow_size_change_callback(DiaSizeSelector *size, gpointer userdata)
1250 {
1251 g_signal_emit(DIA_ARROW_SELECTOR(userdata),
1252 das_signals[DAS_VALUE_CHANGED], 0);
1253 }
1254
1255 static GtkWidget *
create_arrow_menu_item(DiaDynamicMenu * ddm,gchar * name)1256 create_arrow_menu_item(DiaDynamicMenu *ddm, gchar *name)
1257 {
1258 ArrowType atype = arrow_type_from_name(name);
1259 GtkWidget *item = gtk_menu_item_new();
1260 GtkWidget *preview = dia_arrow_preview_new(atype, FALSE);
1261
1262 gtk_widget_show(preview);
1263 gtk_container_add(GTK_CONTAINER(item), preview);
1264 gtk_widget_show(item);
1265 return item;
1266 }
1267
1268 static void
dia_arrow_selector_init(DiaArrowSelector * as,gpointer g_class)1269 dia_arrow_selector_init (DiaArrowSelector *as,
1270 gpointer g_class)
1271 {
1272 GtkWidget *omenu;
1273 GtkWidget *box;
1274 GtkWidget *label;
1275 GtkWidget *size;
1276
1277 GList *arrow_names = get_arrow_names();
1278 omenu = dia_dynamic_menu_new_listbased(create_arrow_menu_item,
1279 as,
1280 _("More arrows"),
1281 arrow_names,
1282 "arrow-menu");
1283 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(omenu), "None");
1284 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(omenu), "Lines");
1285 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(omenu), "Filled Concave");
1286 as->omenu = GTK_OPTION_MENU(omenu);
1287 gtk_box_pack_start(GTK_BOX(as), omenu, FALSE, TRUE, 0);
1288 gtk_widget_show(omenu);
1289
1290 g_signal_connect(DIA_DYNAMIC_MENU(omenu),
1291 "value-changed", G_CALLBACK(arrow_type_change_callback),
1292 as);
1293
1294 box = gtk_hbox_new(FALSE,0);
1295 as->sizebox = GTK_HBOX(box);
1296
1297 label = gtk_label_new(_("Size: "));
1298 as->sizelabel = GTK_LABEL(label);
1299 gtk_box_pack_start_defaults(GTK_BOX(box), label);
1300 gtk_widget_show(label);
1301
1302 size = dia_size_selector_new(0.0, 0.0);
1303 as->size = DIA_SIZE_SELECTOR(size);
1304 gtk_box_pack_start_defaults(GTK_BOX(box), size);
1305 gtk_widget_show(size);
1306 g_signal_connect(size, "value-changed",
1307 G_CALLBACK(arrow_size_change_callback), as);
1308
1309 set_size_sensitivity(as);
1310 gtk_box_pack_start_defaults(GTK_BOX(as), box);
1311
1312 gtk_widget_show(box);
1313 }
1314
1315 GType
dia_arrow_selector_get_type(void)1316 dia_arrow_selector_get_type (void)
1317 {
1318 static GType dfs_type = 0;
1319
1320 if (!dfs_type) {
1321 static const GTypeInfo dfs_info = {
1322 /* sizeof (DiaArrowSelector),*/
1323 sizeof (DiaArrowSelectorClass),
1324 (GBaseInitFunc) NULL,
1325 (GBaseFinalizeFunc) NULL,
1326 (GClassInitFunc) dia_arrow_selector_class_init,
1327 NULL, /* class_finalize */
1328 NULL, /* class_data */
1329 sizeof (DiaArrowSelector),
1330 0, /* n_preallocs */
1331 (GInstanceInitFunc)dia_arrow_selector_init, /* init */
1332 /*
1333 (GtkObjectInitFunc) dia_arrow_selector_init,
1334 NULL,
1335 NULL,
1336 (GtkClassInitFunc) NULL,
1337 */
1338 };
1339
1340 dfs_type = g_type_register_static (GTK_TYPE_VBOX,
1341 "DiaArrowSelector",
1342 &dfs_info, 0);
1343 }
1344
1345 return dfs_type;
1346 }
1347
1348 GtkWidget *
dia_arrow_selector_new()1349 dia_arrow_selector_new ()
1350 {
1351 return GTK_WIDGET ( g_object_new (DIA_TYPE_ARROW_SELECTOR, NULL));
1352 }
1353
1354
1355 Arrow
dia_arrow_selector_get_arrow(DiaArrowSelector * as)1356 dia_arrow_selector_get_arrow(DiaArrowSelector *as)
1357 {
1358 Arrow at;
1359 gchar *arrowname = dia_dynamic_menu_get_entry(DIA_DYNAMIC_MENU(as->omenu));
1360
1361 at.type = arrow_type_from_name(arrowname);
1362 g_free(arrowname);
1363 dia_size_selector_get_size(as->size, &at.width, &at.length);
1364 return at;
1365 }
1366
1367 void
dia_arrow_selector_set_arrow(DiaArrowSelector * as,Arrow arrow)1368 dia_arrow_selector_set_arrow (DiaArrowSelector *as,
1369 Arrow arrow)
1370 {
1371 dia_dynamic_menu_select_entry(DIA_DYNAMIC_MENU(as->omenu),
1372 arrow_get_name_from_type(arrow.type));
1373 set_size_sensitivity(as);
1374 dia_size_selector_set_size(DIA_SIZE_SELECTOR(as->size), arrow.width, arrow.length);
1375 }
1376
1377 /************* DiaFileSelector: ***************/
1378 struct _DiaFileSelector
1379 {
1380 GtkHBox hbox;
1381 GtkEntry *entry;
1382 GtkButton *browse;
1383 GtkWidget *dialog;
1384 gchar *sys_filename;
1385 };
1386
1387 struct _DiaFileSelectorClass
1388 {
1389 GtkHBoxClass parent_class;
1390 };
1391
1392 enum {
1393 DFILE_VALUE_CHANGED,
1394 DFILE_LAST_SIGNAL
1395 };
1396
1397 static guint dfile_signals[DFILE_LAST_SIGNAL] = { 0 };
1398
1399 static void
dia_file_selector_unrealize(GtkWidget * widget)1400 dia_file_selector_unrealize(GtkWidget *widget)
1401 {
1402 DiaFileSelector *fs = DIAFILESELECTOR(widget);
1403
1404 if (fs->dialog != NULL) {
1405 gtk_widget_destroy(GTK_WIDGET(fs->dialog));
1406 fs->dialog = NULL;
1407 }
1408 if (fs->sys_filename) {
1409 g_free(fs->sys_filename);
1410 fs->sys_filename = NULL;
1411 }
1412
1413 (* GTK_WIDGET_CLASS (gtk_type_class(gtk_hbox_get_type ()))->unrealize) (widget);
1414 }
1415
1416 static void
dia_file_selector_class_init(DiaFileSelectorClass * class)1417 dia_file_selector_class_init (DiaFileSelectorClass *class)
1418 {
1419 GtkObjectClass *object_class;
1420 GtkWidgetClass *widget_class;
1421
1422 object_class = (GtkObjectClass*) class;
1423 widget_class = (GtkWidgetClass*) class;
1424 widget_class->unrealize = dia_file_selector_unrealize;
1425
1426 dfile_signals[DFILE_VALUE_CHANGED]
1427 = g_signal_new("value-changed",
1428 G_TYPE_FROM_CLASS(class),
1429 G_SIGNAL_RUN_FIRST,
1430 0, NULL, NULL,
1431 g_cclosure_marshal_VOID__VOID,
1432 G_TYPE_NONE, 0);
1433 }
1434
1435 static void
dia_file_selector_entry_changed(GtkEditable * editable,gpointer data)1436 dia_file_selector_entry_changed(GtkEditable *editable
1437 , gpointer data)
1438 {
1439 DiaFileSelector *fs = DIAFILESELECTOR(data);
1440 g_signal_emit(fs, dfile_signals[DFILE_VALUE_CHANGED], 0);
1441 }
1442
1443 static void
file_open_response_callback(GtkWidget * dialog,gint response,gpointer user_data)1444 file_open_response_callback(GtkWidget *dialog,
1445 gint response,
1446 gpointer user_data)
1447 {
1448 DiaFileSelector *fs =
1449 DIAFILESELECTOR(gtk_object_get_user_data(GTK_OBJECT(dialog)));
1450
1451 if (response == GTK_RESPONSE_ACCEPT || response == GTK_RESPONSE_OK) {
1452 gchar *utf8 = g_filename_to_utf8(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)),
1453 -1, NULL, NULL, NULL);
1454 gtk_entry_set_text(GTK_ENTRY(fs->entry), utf8);
1455 g_free(utf8);
1456 }
1457 gtk_widget_destroy(GTK_WIDGET(dialog));
1458 }
1459
1460 static void
dia_file_selector_browse_pressed(GtkWidget * widget,gpointer data)1461 dia_file_selector_browse_pressed(GtkWidget *widget, gpointer data)
1462 {
1463 GtkWidget *dialog;
1464 DiaFileSelector *fs = DIAFILESELECTOR(data);
1465 gchar *filename;
1466 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1467
1468 if (!GTK_WIDGET_TOPLEVEL(toplevel) || !GTK_WINDOW(toplevel))
1469 toplevel = NULL;
1470
1471 if (fs->dialog == NULL) {
1472 GtkFileFilter *filter;
1473
1474 dialog = fs->dialog =
1475 gtk_file_chooser_dialog_new (_("Select image file"), toplevel ? GTK_WINDOW(toplevel) : NULL,
1476 GTK_FILE_CHOOSER_ACTION_OPEN,
1477 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1478 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1479 NULL);
1480 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1481 g_signal_connect(GTK_OBJECT(dialog), "response",
1482 G_CALLBACK(file_open_response_callback), NULL);
1483 gtk_signal_connect (GTK_OBJECT (fs->dialog), "destroy",
1484 GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1485 &fs->dialog);
1486
1487 filter = gtk_file_filter_new ();
1488 gtk_file_filter_set_name (filter, _("Supported Formats"));
1489 gtk_file_filter_add_pixbuf_formats (filter);
1490 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1491
1492 filter = gtk_file_filter_new ();
1493 gtk_file_filter_set_name (filter, _("All Files"));
1494 gtk_file_filter_add_pattern (filter, "*");
1495 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1496
1497 gtk_object_set_user_data(GTK_OBJECT(dialog), fs);
1498 }
1499
1500 filename = g_filename_from_utf8(gtk_entry_get_text(fs->entry), -1, NULL, NULL, NULL);
1501 /* selecting something in the filechooser officially sucks. See e.g. http://bugzilla.gnome.org/show_bug.cgi?id=307378 */
1502 if (g_path_is_absolute(filename))
1503 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fs->dialog), filename);
1504
1505 g_free(filename);
1506
1507 gtk_widget_show(GTK_WIDGET(fs->dialog));
1508 }
1509
1510 static void
dia_file_selector_init(DiaFileSelector * fs)1511 dia_file_selector_init (DiaFileSelector *fs)
1512 {
1513 /* Here's where we set up the real thing */
1514 fs->dialog = NULL;
1515 fs->sys_filename = NULL;
1516
1517 fs->entry = GTK_ENTRY(gtk_entry_new());
1518 gtk_box_pack_start(GTK_BOX(fs), GTK_WIDGET(fs->entry), FALSE, TRUE, 0);
1519 g_signal_connect(GTK_OBJECT(fs->entry), "changed",
1520 G_CALLBACK(dia_file_selector_entry_changed), fs);
1521 gtk_widget_show(GTK_WIDGET(fs->entry));
1522
1523 fs->browse = GTK_BUTTON(gtk_button_new_with_label(_("Browse")));
1524 gtk_box_pack_start(GTK_BOX(fs), GTK_WIDGET(fs->browse), FALSE, TRUE, 0);
1525 gtk_signal_connect (GTK_OBJECT (fs->browse), "clicked",
1526 (GtkSignalFunc) dia_file_selector_browse_pressed,
1527 fs);
1528 gtk_widget_show(GTK_WIDGET(fs->browse));
1529 }
1530
1531
1532 GtkType
dia_file_selector_get_type(void)1533 dia_file_selector_get_type (void)
1534 {
1535 static GtkType dfs_type = 0;
1536
1537 if (!dfs_type) {
1538 static const GtkTypeInfo dfs_info = {
1539 "DiaFileSelector",
1540 sizeof (DiaFileSelector),
1541 sizeof (DiaFileSelectorClass),
1542 (GtkClassInitFunc) dia_file_selector_class_init,
1543 (GtkObjectInitFunc) dia_file_selector_init,
1544 NULL,
1545 NULL,
1546 (GtkClassInitFunc) NULL,
1547 };
1548
1549 dfs_type = gtk_type_unique (gtk_hbox_get_type (), &dfs_info);
1550
1551 }
1552
1553 return dfs_type;
1554 }
1555
1556 GtkWidget *
dia_file_selector_new()1557 dia_file_selector_new ()
1558 {
1559 return GTK_WIDGET ( gtk_type_new (dia_file_selector_get_type ()));
1560 }
1561
1562 void
dia_file_selector_set_file(DiaFileSelector * fs,gchar * file)1563 dia_file_selector_set_file(DiaFileSelector *fs, gchar *file)
1564 {
1565 /* filename is in system encoding */
1566 gchar *utf8 = g_filename_to_utf8(file, -1, NULL, NULL, NULL);
1567 gtk_entry_set_text(GTK_ENTRY(fs->entry), utf8);
1568 g_free(utf8);
1569 }
1570
1571 const gchar *
dia_file_selector_get_file(DiaFileSelector * fs)1572 dia_file_selector_get_file(DiaFileSelector *fs)
1573 {
1574 /* let it behave like gtk_file_selector_get_file */
1575 g_free(fs->sys_filename);
1576 fs->sys_filename = g_filename_from_utf8(gtk_entry_get_text(GTK_ENTRY(fs->entry)),
1577 -1, NULL, NULL, NULL);
1578 return fs->sys_filename;
1579 }
1580
1581 /************* DiaUnitSpinner: ***************/
1582
1583 /** A Spinner that allows a 'favored' unit to display in. External access
1584 * to the value still happens in cm, but display is in the favored unit.
1585 * Internally, the value is kept in the favored unit to a) allow proper
1586 * limits, and b) avoid rounding problems while editing.
1587 */
1588
1589 static void dia_unit_spinner_init(DiaUnitSpinner *self);
1590
1591 GType
dia_unit_spinner_get_type(void)1592 dia_unit_spinner_get_type(void)
1593 {
1594 static GType us_type = 0;
1595
1596 if (!us_type) {
1597 static const GTypeInfo us_info = {
1598 sizeof(DiaUnitSpinnerClass),
1599 NULL, /* base_init */
1600 NULL, /* base_finalize */
1601 NULL, /* class_init*/
1602 NULL, /* class_finalize */
1603 NULL, /* class_data */
1604 sizeof(DiaUnitSpinner),
1605 0, /* n_preallocs */
1606 (GInstanceInitFunc) dia_unit_spinner_init,
1607 };
1608 us_type = g_type_register_static(GTK_TYPE_SPIN_BUTTON,
1609 "DiaUnitSpinner",
1610 &us_info, 0);
1611 }
1612 return us_type;
1613 }
1614
1615
1616 static void
dia_unit_spinner_init(DiaUnitSpinner * self)1617 dia_unit_spinner_init(DiaUnitSpinner *self)
1618 {
1619 self->unit_num = DIA_UNIT_CENTIMETER;
1620 }
1621
1622 /*
1623 Callback functions for the "input" and "output" signals emitted by
1624 GtkSpinButton. All the normal work is done by the spin button, we
1625 simply modify how the text in the GtkEntry is treated.
1626 */
1627 static gboolean
1628 dia_unit_spinner_input(DiaUnitSpinner *self, gdouble *value);
1629 static gboolean dia_unit_spinner_output(DiaUnitSpinner *self);
1630
1631 GtkWidget *
dia_unit_spinner_new(GtkAdjustment * adjustment,DiaUnit adj_unit)1632 dia_unit_spinner_new(GtkAdjustment *adjustment, DiaUnit adj_unit)
1633 {
1634 DiaUnitSpinner *self;
1635
1636 if (adjustment) {
1637 g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), NULL);
1638 }
1639
1640 self = gtk_type_new(dia_unit_spinner_get_type());
1641 self->unit_num = adj_unit;
1642
1643 gtk_spin_button_configure(GTK_SPIN_BUTTON(self),
1644 adjustment, 0.0, units[adj_unit].digits);
1645
1646 g_signal_connect(GTK_SPIN_BUTTON(self), "output",
1647 G_CALLBACK(dia_unit_spinner_output),
1648 NULL);
1649 g_signal_connect(GTK_SPIN_BUTTON(self), "input",
1650 G_CALLBACK(dia_unit_spinner_input),
1651 NULL);
1652
1653 return GTK_WIDGET(self);
1654 }
1655
1656 static gboolean
dia_unit_spinner_input(DiaUnitSpinner * self,gdouble * value)1657 dia_unit_spinner_input(DiaUnitSpinner *self, gdouble *value)
1658 {
1659 gfloat val, factor = 1.0;
1660 gchar *extra = NULL;
1661
1662 val = g_strtod(gtk_entry_get_text(GTK_ENTRY(self)), &extra);
1663
1664 /* get rid of extra white space after number */
1665 while (*extra && g_ascii_isspace(*extra)) extra++;
1666 if (*extra) {
1667 int i;
1668
1669 for (i = 0; units[i].name != NULL; i++)
1670 if (!g_ascii_strcasecmp(units[i].unit, extra)) {
1671 factor = units[i].factor / units[self->unit_num].factor;
1672 break;
1673 }
1674 }
1675 /* convert to prefered units */
1676 val *= factor;
1677
1678 /* Store value in the location provided by the signal emitter. */
1679 *value = val;
1680
1681 /* Return true, so that the default input function is not invoked. */
1682 return TRUE;
1683 }
1684
dia_unit_spinner_output(DiaUnitSpinner * self)1685 static gboolean dia_unit_spinner_output(DiaUnitSpinner *self)
1686 {
1687 char buf[256];
1688
1689 GtkSpinButton *sbutton = GTK_SPIN_BUTTON(self);
1690 GtkAdjustment *adjustment = gtk_spin_button_get_adjustment(sbutton);
1691
1692 g_snprintf(buf, sizeof(buf), "%0.*f %s",
1693 gtk_spin_button_get_digits(sbutton),
1694 gtk_adjustment_get_value(adjustment),
1695 units[self->unit_num].unit);
1696 gtk_entry_set_text(GTK_ENTRY(self), buf);
1697
1698 /* Return true, so that the default output function is not invoked. */
1699 return TRUE;
1700 }
1701
1702 /** Set the value (in cm).
1703 * */
1704 void
dia_unit_spinner_set_value(DiaUnitSpinner * self,gdouble val)1705 dia_unit_spinner_set_value(DiaUnitSpinner *self, gdouble val)
1706 {
1707 GtkSpinButton *sbutton = GTK_SPIN_BUTTON(self);
1708
1709 gtk_spin_button_set_value(sbutton,
1710 val /
1711 (units[self->unit_num].factor /
1712 units[DIA_UNIT_CENTIMETER].factor));
1713 }
1714
1715 /** Get the value (in cm) */
1716 gdouble
dia_unit_spinner_get_value(DiaUnitSpinner * self)1717 dia_unit_spinner_get_value(DiaUnitSpinner *self)
1718 {
1719 GtkSpinButton *sbutton = GTK_SPIN_BUTTON(self);
1720
1721 return gtk_spin_button_get_value(sbutton) *
1722 (units[self->unit_num].factor / units[DIA_UNIT_CENTIMETER].factor);
1723 }
1724
1725 /* Must manipulate the limit values through this to also consider unit.
1726 * Given value is in centimeter.
1727 */
1728 void
dia_unit_spinner_set_upper(DiaUnitSpinner * self,gdouble val)1729 dia_unit_spinner_set_upper (DiaUnitSpinner *self, gdouble val)
1730 {
1731 val /= (units[self->unit_num].factor / units[DIA_UNIT_CENTIMETER].factor);
1732
1733 gtk_adjustment_set_upper (
1734 gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(self)), val);
1735 }
1736 GList *
get_units_name_list(void)1737 get_units_name_list(void)
1738 {
1739 int i;
1740 static GList *name_list = NULL;
1741
1742 if (name_list == NULL) {
1743 for (i = 0; units[i].name != NULL; i++) {
1744 name_list = g_list_append(name_list, units[i].name);
1745 }
1746 }
1747
1748 return name_list;
1749 }
1750
1751 /* ************************ Dynamic menus ************************ */
1752
1753 static void dia_dynamic_menu_class_init(DiaDynamicMenuClass *class);
1754 static void dia_dynamic_menu_init(DiaDynamicMenu *self);
1755 static void dia_dynamic_menu_create_sublist(DiaDynamicMenu *ddm,
1756 GList *items,
1757 DDMCreateItemFunc create);
1758 static void dia_dynamic_menu_create_menu(DiaDynamicMenu *ddm);
1759 static void dia_dynamic_menu_destroy(GtkObject *object);
1760
1761 enum {
1762 DDM_VALUE_CHANGED,
1763 DDM_LAST_SIGNAL
1764 };
1765
1766 static guint ddm_signals[DDM_LAST_SIGNAL] = { 0 };
1767
1768 GtkType
dia_dynamic_menu_get_type(void)1769 dia_dynamic_menu_get_type(void)
1770 {
1771 static GtkType us_type = 0;
1772
1773 if (!us_type) {
1774 static const GtkTypeInfo us_info = {
1775 "DiaDynamicMenu",
1776 sizeof(DiaDynamicMenu),
1777 sizeof(DiaDynamicMenuClass),
1778 (GtkClassInitFunc) dia_dynamic_menu_class_init,
1779 (GtkObjectInitFunc) dia_dynamic_menu_init,
1780 NULL,
1781 NULL,
1782 (GtkClassInitFunc) NULL,
1783 };
1784 us_type = gtk_type_unique(gtk_option_menu_get_type(), &us_info);
1785 }
1786 return us_type;
1787 }
1788
1789 static void
dia_dynamic_menu_class_init(DiaDynamicMenuClass * class)1790 dia_dynamic_menu_class_init(DiaDynamicMenuClass *class)
1791 {
1792 GtkObjectClass *object_class = (GtkObjectClass*)class;
1793
1794 object_class->destroy = dia_dynamic_menu_destroy;
1795
1796 ddm_signals[DDM_VALUE_CHANGED]
1797 = g_signal_new("value-changed",
1798 G_TYPE_FROM_CLASS(class),
1799 G_SIGNAL_RUN_FIRST,
1800 0, NULL, NULL,
1801 g_cclosure_marshal_VOID__VOID,
1802 G_TYPE_NONE, 0);
1803 }
1804
1805 static void
dia_dynamic_menu_init(DiaDynamicMenu * self)1806 dia_dynamic_menu_init(DiaDynamicMenu *self)
1807 {
1808 }
1809
1810 void
dia_dynamic_menu_destroy(GtkObject * object)1811 dia_dynamic_menu_destroy(GtkObject *object)
1812 {
1813 DiaDynamicMenu *ddm = DIA_DYNAMIC_MENU(object);
1814 GtkObjectClass *parent_class = GTK_OBJECT_CLASS(g_type_class_peek_parent(GTK_OBJECT_GET_CLASS(object)));
1815
1816 if (ddm->active)
1817 g_free(ddm->active);
1818 ddm->active = NULL;
1819
1820 if (parent_class->destroy)
1821 (* parent_class->destroy) (object);
1822 }
1823
1824 /** Create a new dynamic menu. The entries are represented with
1825 * gpointers.
1826 * @param create A function that creates menuitems from gpointers.
1827 * @param otheritem A menuitem that can be selected by the user to
1828 * add more entries, for instance making a dialog box or a submenu.
1829 * @param persist A string naming this menu for persistence purposes, or NULL.
1830
1831 * @return A new menu
1832 */
1833 GtkWidget *
dia_dynamic_menu_new(DDMCreateItemFunc create,gpointer userdata,GtkMenuItem * otheritem,gchar * persist)1834 dia_dynamic_menu_new(DDMCreateItemFunc create,
1835 gpointer userdata,
1836 GtkMenuItem *otheritem, gchar *persist)
1837 {
1838 DiaDynamicMenu *ddm;
1839
1840 g_assert(persist != NULL);
1841
1842 ddm = DIA_DYNAMIC_MENU ( gtk_type_new (dia_dynamic_menu_get_type ()));
1843
1844 ddm->create_func = create;
1845 ddm->userdata = userdata;
1846 ddm->other_item = otheritem;
1847 ddm->persistent_name = persist;
1848 ddm->cols = 1;
1849
1850 persistence_register_list(persist);
1851
1852 dia_dynamic_menu_create_menu(ddm);
1853
1854 return GTK_WIDGET(ddm);
1855 }
1856
1857 /** Select the given entry, adding it if necessary */
1858 void
dia_dynamic_menu_select_entry(DiaDynamicMenu * ddm,const gchar * name)1859 dia_dynamic_menu_select_entry(DiaDynamicMenu *ddm, const gchar *name)
1860 {
1861 gint add_result = dia_dynamic_menu_add_entry(ddm, name);
1862 if (add_result == 0) {
1863 GList *tmp;
1864 int i = 0;
1865 for (tmp = ddm->default_entries; tmp != NULL;
1866 tmp = g_list_next(tmp), i++) {
1867 if (!g_ascii_strcasecmp(tmp->data, name))
1868 gtk_option_menu_set_history(GTK_OPTION_MENU(ddm), i);
1869 }
1870 /* Not there after all? */
1871 } else {
1872 if (ddm->default_entries != NULL)
1873 gtk_option_menu_set_history(GTK_OPTION_MENU(ddm),
1874 g_list_length(ddm->default_entries)+1);
1875 else
1876 gtk_option_menu_set_history(GTK_OPTION_MENU(ddm), 0);
1877 }
1878
1879 g_free(ddm->active);
1880 ddm->active = g_strdup(name);
1881 g_signal_emit(GTK_OBJECT(ddm), ddm_signals[DDM_VALUE_CHANGED], 0);
1882 }
1883
1884 static void
dia_dynamic_menu_activate(GtkWidget * item,gpointer userdata)1885 dia_dynamic_menu_activate(GtkWidget *item, gpointer userdata)
1886 {
1887 DiaDynamicMenu *ddm = DIA_DYNAMIC_MENU(userdata);
1888 gchar *name = g_object_get_data(G_OBJECT(item), "ddm_name");
1889 dia_dynamic_menu_select_entry(ddm, name);
1890 }
1891
1892 static GtkWidget *
dia_dynamic_menu_create_string_item(DiaDynamicMenu * ddm,gchar * string)1893 dia_dynamic_menu_create_string_item(DiaDynamicMenu *ddm, gchar *string)
1894 {
1895 GtkWidget *item = gtk_menu_item_new_with_label(gettext(string));
1896 return item;
1897 }
1898
1899 /** Utility function for dynamic menus that are entirely based on the
1900 * labels in the menu.
1901 */
1902 GtkWidget *
dia_dynamic_menu_new_stringbased(GtkMenuItem * otheritem,gpointer userdata,gchar * persist)1903 dia_dynamic_menu_new_stringbased(GtkMenuItem *otheritem,
1904 gpointer userdata,
1905 gchar *persist)
1906 {
1907 GtkWidget *ddm = dia_dynamic_menu_new(dia_dynamic_menu_create_string_item,
1908 userdata,
1909 otheritem, persist);
1910 return ddm;
1911 }
1912
1913 /** Utility function for dynamic menus that are based on a submenu with
1914 * many entries. This is useful for allowing the user to get a smaller
1915 * subset menu out of a set too large to be easily handled by a menu.
1916 */
1917 GtkWidget *
dia_dynamic_menu_new_listbased(DDMCreateItemFunc create,gpointer userdata,gchar * other_label,GList * items,gchar * persist)1918 dia_dynamic_menu_new_listbased(DDMCreateItemFunc create,
1919 gpointer userdata,
1920 gchar *other_label, GList *items,
1921 gchar *persist)
1922 {
1923 GtkWidget *item = gtk_menu_item_new_with_label(other_label);
1924 GtkWidget *ddm = dia_dynamic_menu_new(create, userdata,
1925 GTK_MENU_ITEM(item), persist);
1926 dia_dynamic_menu_create_sublist(DIA_DYNAMIC_MENU(ddm), items, create);
1927
1928 gtk_widget_show(item);
1929 return ddm;
1930 }
1931
1932 /** Utility function for dynamic menus that allow selection from a large
1933 * number of strings.
1934 */
1935 GtkWidget *
dia_dynamic_menu_new_stringlistbased(gchar * other_label,GList * items,gpointer userdata,gchar * persist)1936 dia_dynamic_menu_new_stringlistbased(gchar *other_label,
1937 GList *items,
1938 gpointer userdata,
1939 gchar *persist)
1940 {
1941 return dia_dynamic_menu_new_listbased(dia_dynamic_menu_create_string_item,
1942 userdata,
1943 other_label, items, persist);
1944 }
1945
1946 static void
dia_dynamic_menu_create_sublist(DiaDynamicMenu * ddm,GList * items,DDMCreateItemFunc create)1947 dia_dynamic_menu_create_sublist(DiaDynamicMenu *ddm,
1948 GList *items, DDMCreateItemFunc create)
1949 {
1950 GtkWidget *item = GTK_WIDGET(ddm->other_item);
1951
1952 GtkWidget *submenu = gtk_menu_new();
1953
1954 for (; items != NULL; items = g_list_next(items)) {
1955 GtkWidget *submenuitem = (create)(ddm, items->data);
1956 /* Set callback function to cause addition of item */
1957 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), submenuitem);
1958 g_object_set_data(G_OBJECT(submenuitem), "ddm_name", items->data);
1959 g_signal_connect(submenuitem, "activate",
1960 G_CALLBACK(dia_dynamic_menu_activate), ddm);
1961 gtk_widget_show(submenuitem);
1962 }
1963
1964 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
1965 gtk_widget_show(submenu);
1966 }
1967
1968 /** Add a new default entry to this menu.
1969 * The default entries are always shown, also after resets, above the
1970 * other entries. Possible uses are standard fonts or common colors.
1971 * The entry is added at the end of the default entries section.
1972 * Do not add too many default entries.
1973 *
1974 * @param ddm A dynamic menu to add the entry to.
1975 * @param entry An entry for the menu.
1976 */
1977 void
dia_dynamic_menu_add_default_entry(DiaDynamicMenu * ddm,const gchar * entry)1978 dia_dynamic_menu_add_default_entry(DiaDynamicMenu *ddm, const gchar *entry)
1979 {
1980 ddm->default_entries = g_list_append(ddm->default_entries,
1981 g_strdup(entry));
1982
1983 dia_dynamic_menu_create_menu(ddm);
1984 }
1985
1986 /** Set the number of columns this menu uses (default 1)
1987 * @param cols Desired # of columns (>= 1)
1988 */
1989 void
dia_dynamic_menu_set_columns(DiaDynamicMenu * ddm,gint cols)1990 dia_dynamic_menu_set_columns(DiaDynamicMenu *ddm, gint cols)
1991 {
1992 ddm->cols = cols;
1993
1994 dia_dynamic_menu_create_menu(ddm);
1995 }
1996
1997 /** Add a new entry to this menu. The placement depends on what sorting
1998 * system has been chosen with dia_dynamic_menu_set_sorting_method().
1999 *
2000 * @param ddm A dynamic menu to add the entry to.
2001 * @param entry An entry for the menu.
2002 *
2003 * @returns 0 if the entry was one of the default entries.
2004 * 1 if the entry was already there.
2005 * 2 if the entry got added.
2006 */
2007 gint
dia_dynamic_menu_add_entry(DiaDynamicMenu * ddm,const gchar * entry)2008 dia_dynamic_menu_add_entry(DiaDynamicMenu *ddm, const gchar *entry)
2009 {
2010 GList *tmp;
2011 gboolean existed;
2012
2013 for (tmp = ddm->default_entries; tmp != NULL; tmp = g_list_next(tmp)) {
2014 if (!g_ascii_strcasecmp(tmp->data, entry))
2015 return 0;
2016 }
2017 existed = persistent_list_add(ddm->persistent_name, entry);
2018
2019 dia_dynamic_menu_create_menu(ddm);
2020
2021 return existed?1:2;
2022 }
2023
2024 /** Returns the currently selected entry.
2025 * @returns The name of the entry that is currently selected. This
2026 * string should be freed by the caller. */
2027 gchar *
dia_dynamic_menu_get_entry(DiaDynamicMenu * ddm)2028 dia_dynamic_menu_get_entry(DiaDynamicMenu *ddm)
2029 {
2030 return g_strdup(ddm->active);
2031 }
2032
2033 /** Rebuild the actual menu of a DDM.
2034 * Ignores columns for now.
2035 */
2036 static void
dia_dynamic_menu_create_menu(DiaDynamicMenu * ddm)2037 dia_dynamic_menu_create_menu(DiaDynamicMenu *ddm)
2038 {
2039 GtkWidget *sep;
2040 GList *tmplist;
2041 GtkWidget *menu;
2042 GtkWidget *item;
2043
2044 g_object_ref(G_OBJECT(ddm->other_item));
2045 menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(ddm));
2046 if (menu != NULL) {
2047 gtk_container_remove(GTK_CONTAINER(menu), GTK_WIDGET(ddm->other_item));
2048 gtk_container_foreach(GTK_CONTAINER(menu),
2049 (GtkCallback)gtk_widget_destroy, NULL);
2050 gtk_option_menu_remove_menu(GTK_OPTION_MENU(ddm));
2051 }
2052
2053 menu = gtk_menu_new();
2054
2055 if (ddm->default_entries != NULL) {
2056 for (tmplist = ddm->default_entries; tmplist != NULL; tmplist = g_list_next(tmplist)) {
2057 GtkWidget *item = (ddm->create_func)(ddm, tmplist->data);
2058 g_object_set_data(G_OBJECT(item), "ddm_name", tmplist->data);
2059 g_signal_connect(G_OBJECT(item), "activate",
2060 G_CALLBACK(dia_dynamic_menu_activate), ddm);
2061 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2062 gtk_widget_show(item);
2063 }
2064 sep = gtk_separator_menu_item_new();
2065 gtk_widget_show(sep);
2066 gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
2067 }
2068
2069 for (tmplist = persistent_list_get_glist(ddm->persistent_name);
2070 tmplist != NULL; tmplist = g_list_next(tmplist)) {
2071 GtkWidget *item = (ddm->create_func)(ddm, tmplist->data);
2072 g_object_set_data(G_OBJECT(item), "ddm_name", tmplist->data);
2073 g_signal_connect(G_OBJECT(item), "activate",
2074 G_CALLBACK(dia_dynamic_menu_activate), ddm);
2075 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2076 gtk_widget_show(item);
2077 }
2078 sep = gtk_separator_menu_item_new();
2079 gtk_widget_show(sep);
2080 gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
2081
2082 gtk_menu_shell_append(GTK_MENU_SHELL(menu), GTK_WIDGET(ddm->other_item));
2083 g_object_unref(G_OBJECT(ddm->other_item));
2084 /* Eventually reset item here */
2085 gtk_widget_show(menu);
2086
2087 item = gtk_menu_item_new_with_label(_("Reset menu"));
2088 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2089 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(dia_dynamic_menu_reset), ddm);
2090 gtk_widget_show(item);
2091
2092 gtk_option_menu_set_menu(GTK_OPTION_MENU(ddm), menu);
2093
2094 gtk_option_menu_set_history(GTK_OPTION_MENU(ddm), 0);
2095 }
2096
2097 /** Select the method used for sorting the non-default entries.
2098 * @param ddm A dynamic menu
2099 * @param sort The way the non-default entries in the menu should be sorted.
2100 */
2101 void
dia_dynamic_menu_set_sorting_method(DiaDynamicMenu * ddm,DdmSortType sort)2102 dia_dynamic_menu_set_sorting_method(DiaDynamicMenu *ddm, DdmSortType sort)
2103 {
2104 }
2105
2106 /** Reset the non-default entries of a menu
2107 */
2108 void
dia_dynamic_menu_reset(GtkWidget * item,gpointer userdata)2109 dia_dynamic_menu_reset(GtkWidget *item, gpointer userdata)
2110 {
2111 DiaDynamicMenu *ddm = DIA_DYNAMIC_MENU(userdata);
2112 PersistentList *plist = persistent_list_get(ddm->persistent_name);
2113 gchar *active = dia_dynamic_menu_get_entry(ddm);
2114 g_list_foreach(plist->glist, (GFunc)g_free, NULL);
2115 g_list_free(plist->glist);
2116 plist->glist = NULL;
2117 dia_dynamic_menu_create_menu(ddm);
2118 if (active)
2119 dia_dynamic_menu_select_entry(ddm, active);
2120 g_free(active);
2121 }
2122
2123 /** Set the maximum number of non-default entries.
2124 * If more than this number of entries are added, the least recently
2125 * selected ones are removed. */
2126 void
dia_dynamic_menu_set_max_entries(DiaDynamicMenu * ddm,gint max)2127 dia_dynamic_menu_set_max_entries(DiaDynamicMenu *ddm, gint max)
2128 {
2129 }
2130
2131
2132 /* ************************ Misc. util functions ************************ */
2133 struct image_pair { GtkWidget *on; GtkWidget *off; };
2134
2135 static void
dia_toggle_button_swap_images(GtkToggleButton * widget,gpointer data)2136 dia_toggle_button_swap_images(GtkToggleButton *widget,
2137 gpointer data)
2138 {
2139 struct image_pair *images = (struct image_pair *)data;
2140 if (gtk_toggle_button_get_active(widget)) {
2141 gtk_container_remove(GTK_CONTAINER(widget),
2142 gtk_bin_get_child(GTK_BIN(widget)));
2143 gtk_container_add(GTK_CONTAINER(widget),
2144 images->on);
2145
2146 } else {
2147 gtk_container_remove(GTK_CONTAINER(widget),
2148 gtk_bin_get_child(GTK_BIN(widget)));
2149 gtk_container_add(GTK_CONTAINER(widget),
2150 images->off);
2151 }
2152 }
2153
2154 static void
dia_toggle_button_destroy(GtkWidget * widget,gpointer data)2155 dia_toggle_button_destroy(GtkWidget *widget, gpointer data)
2156 {
2157 struct image_pair *images = (struct image_pair *)data;
2158
2159 if (images->on)
2160 g_object_unref(images->on);
2161 images->on = NULL;
2162 if (images->off)
2163 g_object_unref(images->off);
2164 images->off = NULL;
2165 if (images)
2166 g_free(images);
2167 images = NULL;
2168 }
2169
2170 /** Create a toggle button given two image widgets for on and off */
2171 static GtkWidget *
dia_toggle_button_new(GtkWidget * on_widget,GtkWidget * off_widget)2172 dia_toggle_button_new(GtkWidget *on_widget, GtkWidget *off_widget)
2173 {
2174 GtkWidget *button = gtk_toggle_button_new();
2175 GtkRcStyle *rcstyle;
2176 GValue *prop;
2177 gint i;
2178 struct image_pair *images;
2179
2180 images = g_new(struct image_pair, 1);
2181 /* Since these may not be added at any point, make sure to
2182 * sink them. */
2183 images->on = on_widget;
2184 g_object_ref(G_OBJECT(images->on));
2185 gtk_object_sink(GTK_OBJECT(images->on));
2186 gtk_widget_show(images->on);
2187
2188 images->off = off_widget;
2189 g_object_ref(G_OBJECT(images->off));
2190 gtk_object_sink(GTK_OBJECT(images->off));
2191 gtk_widget_show(images->off);
2192
2193 /* Make border as small as possible */
2194 gtk_misc_set_padding(GTK_MISC(images->on), 0, 0);
2195 gtk_misc_set_padding(GTK_MISC(images->off), 0, 0);
2196 GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(button), GTK_CAN_FOCUS);
2197 GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(button), GTK_CAN_DEFAULT);
2198
2199 rcstyle = gtk_rc_style_new ();
2200 rcstyle->xthickness = rcstyle->ythickness = 0;
2201 gtk_widget_modify_style (button, rcstyle);
2202 gtk_rc_style_unref (rcstyle);
2203
2204 prop = g_new0(GValue, 1);
2205 g_value_init(prop, G_TYPE_INT);
2206 gtk_widget_style_get_property(GTK_WIDGET(button), "focus-padding", prop);
2207 i = g_value_get_int(prop);
2208 g_value_set_int(prop, 0);
2209 g_free(prop);
2210
2211 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
2212 /* gtk_button_set_focus_on_click(GTK_BUTTON(button), FALSE);*/
2213 gtk_container_set_border_width(GTK_CONTAINER(button), 0);
2214
2215 gtk_container_add(GTK_CONTAINER(button), images->off);
2216
2217 g_signal_connect(G_OBJECT(button), "toggled",
2218 G_CALLBACK(dia_toggle_button_swap_images), images);
2219 g_signal_connect(G_OBJECT(button), "destroy",
2220 G_CALLBACK(dia_toggle_button_destroy), images);
2221
2222 return button;
2223 }
2224
2225 /** Create a toggle button with two icons (created with gdk-pixbuf-csource,
2226 * for instance). The icons represent on and off.
2227 */
2228 GtkWidget *
dia_toggle_button_new_with_icons(const guint8 * on_icon,const guint8 * off_icon)2229 dia_toggle_button_new_with_icons(const guint8 *on_icon,
2230 const guint8 *off_icon)
2231 {
2232 GdkPixbuf *p1, *p2;
2233
2234 p1 = gdk_pixbuf_new_from_inline(-1, on_icon, FALSE, NULL);
2235 p2 = gdk_pixbuf_new_from_inline(-1, off_icon, FALSE, NULL);
2236
2237 return dia_toggle_button_new(gtk_image_new_from_pixbuf(p1),
2238 gtk_image_new_from_pixbuf(p2));
2239 }
2240
2241
2242