UML class fix bigtime.
[dia.git] / lib / widgets.c
blobc0c932119d242c154d2f06375f5323248a104d2c
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 #include <config.h>
20 #include <string.h>
21 #include "intl.h"
22 #undef GTK_DISABLE_DEPRECATED /* GtkOptionMenu, ... */
23 #include "widgets.h"
24 #include "message.h"
25 #include "dia_dirs.h"
26 #include "arrows.h"
27 #include "diaarrowchooser.h"
28 #include "dialinechooser.h"
29 #include "persistence.h"
30 #include "dia-lib-icons.h"
32 #include <stdlib.h>
33 #include <glib.h>
34 #include <gdk/gdk.h>
35 #include <gtk/gtk.h>
36 #include <pango/pango.h>
37 #include <stdio.h>
38 #include <time.h>
39 #include <gdk/gdkkeysyms.h>
41 #include "diagtkfontsel.h"
43 /************* DiaSizeSelector: ***************/
44 /* A widget that selects two sizes, width and height, optionally keeping
45 * aspect ratio. When created, aspect ratio is locked, but the user can
46 * unlock it. The current users do not store aspect ratio, so we have
47 * to give a good default.
49 struct _DiaSizeSelector
51 GtkHBox hbox;
52 GtkSpinButton *width, *height;
53 GtkToggleButton *aspect_locked;
54 real ratio;
55 GtkAdjustment *last_adjusted;
58 struct _DiaSizeSelectorClass
60 GtkHBoxClass parent_class;
63 static void
64 dia_size_selector_unrealize(GtkWidget *widget)
66 (* GTK_WIDGET_CLASS (gtk_type_class(gtk_hbox_get_type ()))->unrealize) (widget);
69 static void
70 dia_size_selector_class_init (DiaSizeSelectorClass *class)
72 GtkObjectClass *object_class;
73 GtkWidgetClass *widget_class;
75 object_class = (GtkObjectClass*) class;
76 widget_class = (GtkWidgetClass*) class;
77 widget_class->unrealize = dia_size_selector_unrealize;
80 static void
81 dia_size_selector_adjust_width(DiaSizeSelector *ss)
83 real height =
84 gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(ss->height));
85 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ss->width), height*ss->ratio);
88 static void
89 dia_size_selector_adjust_height(DiaSizeSelector *ss)
91 real width =
92 gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(ss->width));
93 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ss->height), width/ss->ratio);
96 static void
97 dia_size_selector_ratio_callback(GtkAdjustment *limits, gpointer userdata)
99 static gboolean in_progress;
100 DiaSizeSelector *ss = DIA_SIZE_SELECTOR(userdata);
102 ss->last_adjusted = limits;
104 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ss->aspect_locked))
105 || ss->ratio == 0.0)
106 return;
108 if (in_progress) return;
109 in_progress = TRUE;
111 if (limits == gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ss->width))) {
112 dia_size_selector_adjust_height(ss);
113 } else {
114 dia_size_selector_adjust_width(ss);
117 in_progress = FALSE;
120 /** Update the ratio of this DSS to be the ratio of width to height.
121 * If height is 0, ratio becomes 0.0.
123 static void
124 dia_size_selector_set_ratio(DiaSizeSelector *ss, real width, real height)
126 if (height > 0.0)
127 ss->ratio = width/height;
128 else
129 ss->ratio = 0.0;
132 static void
133 dia_size_selector_lock_pressed(GtkWidget *widget, gpointer data)
135 DiaSizeSelector *ss = DIA_SIZE_SELECTOR(data);
137 dia_size_selector_set_ratio(ss,
138 gtk_spin_button_get_value(GTK_SPIN_BUTTON(ss->width)),
139 gtk_spin_button_get_value(GTK_SPIN_BUTTON(ss->height)));
142 /* Possible args: Init width, init height, digits */
144 static void
145 dia_size_selector_init (DiaSizeSelector *ss)
147 GtkAdjustment *adj;
149 ss->ratio = 0.0;
150 /* Here's where we set up the real thing */
151 adj = GTK_ADJUSTMENT(gtk_adjustment_new(1.0, 0.01, 10,
152 0.1, 1.0, 1.0));
153 ss->width = GTK_SPIN_BUTTON(gtk_spin_button_new(adj, 1.0, 2));
154 gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(ss->width), TRUE);
155 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(ss->width), TRUE);
156 gtk_box_pack_start(GTK_BOX(ss), GTK_WIDGET(ss->width), FALSE, TRUE, 0);
157 gtk_widget_show(GTK_WIDGET(ss->width));
159 adj = GTK_ADJUSTMENT(gtk_adjustment_new(1.0, 0.01, 10,
160 0.1, 1.0, 1.0));
161 ss->height = GTK_SPIN_BUTTON(gtk_spin_button_new(adj, 1.0, 2));
162 gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(ss->height), TRUE);
163 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(ss->height), TRUE);
164 gtk_box_pack_start(GTK_BOX(ss), GTK_WIDGET(ss->height), FALSE, TRUE, 0);
165 gtk_widget_show(GTK_WIDGET(ss->height));
167 /* Replace label with images */
168 /* should make sure they're both unallocated when the widget dies.
169 * That should happen in the "destroy" handler, where both should
170 * be unref'd */
171 ss->aspect_locked =
172 GTK_TOGGLE_BUTTON(dia_toggle_button_new_with_icons
173 (dia_unbroken_chain_icon,
174 dia_broken_chain_icon));
176 gtk_container_set_border_width(GTK_CONTAINER(ss->aspect_locked), 0);
178 gtk_box_pack_start(GTK_BOX(ss), GTK_WIDGET(ss->aspect_locked), FALSE, TRUE, 0);
179 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ss->aspect_locked), TRUE);
180 gtk_widget_show(GTK_WIDGET(ss->aspect_locked));
182 gtk_signal_connect (GTK_OBJECT (ss->aspect_locked), "clicked",
183 (GtkSignalFunc) dia_size_selector_lock_pressed,
184 ss);
185 /* Make sure that the aspect ratio stays the same */
186 g_signal_connect(GTK_OBJECT(gtk_spin_button_get_adjustment(ss->width)),
187 "value_changed",
188 G_CALLBACK(dia_size_selector_ratio_callback), (gpointer)ss);
189 g_signal_connect(GTK_OBJECT(gtk_spin_button_get_adjustment(ss->height)),
190 "value_changed",
191 G_CALLBACK(dia_size_selector_ratio_callback), (gpointer)ss);
194 GtkType
195 dia_size_selector_get_type (void)
197 static GtkType dss_type = 0;
199 if (!dss_type) {
200 static const GtkTypeInfo dss_info = {
201 "DiaSizeSelector",
202 sizeof (DiaSizeSelector),
203 sizeof (DiaSizeSelectorClass),
204 (GtkClassInitFunc) dia_size_selector_class_init,
205 (GtkObjectInitFunc) dia_size_selector_init,
206 NULL,
207 NULL,
208 (GtkClassInitFunc) NULL,
211 dss_type = gtk_type_unique (gtk_hbox_get_type (), &dss_info);
215 return dss_type;
218 GtkWidget *
219 dia_size_selector_new (real width, real height)
221 GtkWidget *wid;
223 wid = GTK_WIDGET ( gtk_type_new (dia_size_selector_get_type ()));
224 dia_size_selector_set_size(DIA_SIZE_SELECTOR(wid), width, height);
225 return wid;
228 void
229 dia_size_selector_set_size(DiaSizeSelector *ss, real width, real height)
231 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ss->width), width);
232 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ss->height), height);
234 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ss->aspect_locked),
235 fabs(width - height) < 0.000001);
237 dia_size_selector_set_ratio(ss, width, height);
240 void
241 dia_size_selector_set_locked(DiaSizeSelector *ss, gboolean locked)
243 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ss->aspect_locked))
244 && locked) {
245 dia_size_selector_set_ratio(ss,
246 gtk_spin_button_get_value(GTK_SPIN_BUTTON(ss->width)),
247 gtk_spin_button_get_value(GTK_SPIN_BUTTON(ss->height)));
249 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ss->aspect_locked), locked);
252 gboolean
253 dia_size_selector_get_size(DiaSizeSelector *ss, real *width, real *height)
255 *width = gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(ss->width));
256 *height = gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(ss->height));
257 return gtk_toggle_button_get_active(ss->aspect_locked);
260 /************* DiaFontSelector: ***************/
262 struct _DiaFontSelector
264 GtkHBox hbox;
266 GtkOptionMenu *font_omenu;
267 GtkOptionMenu *style_omenu;
268 GtkMenu *style_menu;
271 struct _DiaFontSelectorClass
273 GtkHBoxClass parent_class;
277 /* New and improved font selector: Contains the three standard fonts
278 * and an 'Other fonts...' entry that opens the font dialog. The fonts
279 * selected in the font dialog are persistently added to the menu.
281 * +----------------+
282 * | Sans |
283 * | Serif |
284 * | Monospace |
285 * | -------------- |
286 * | Bodini |
287 * | CurlyGothic |
288 * | OldWestern |
289 * | -------------- |
290 * | Other fonts... |
291 * +----------------+
294 static void dia_font_selector_fontmenu_callback(DiaDynamicMenu *button,
295 const gchar *fontname,
296 gpointer data);
297 static void dia_font_selector_set_styles(DiaFontSelector *fs,
298 const gchar *name,
299 DiaFontStyle dia_style);
300 static void dia_font_selector_set_style_menu(DiaFontSelector *fs,
301 PangoFontFamily *pff,
302 DiaFontStyle dia_style);
304 static void
305 dia_font_selector_class_init (DiaFontSelectorClass *class)
307 GtkObjectClass *object_class;
309 object_class = (GtkObjectClass*) class;
312 static int
313 dia_font_selector_sort_fonts(const void *p1, const void *p2)
315 const gchar *n1 = pango_font_family_get_name(PANGO_FONT_FAMILY(*(void**)p1));
316 const gchar *n2 = pango_font_family_get_name(PANGO_FONT_FAMILY(*(void**)p2));
317 return g_strcasecmp(n1, n2);
320 static gchar*
321 replace_ampersands(gchar* string)
323 gchar** pieces = g_strsplit(string, "&", -1);
324 gchar* escaped = g_strjoinv("&amp;", pieces);
325 g_strfreev(pieces);
326 return escaped;
329 static GtkWidget *
330 dia_font_selector_create_string_item(DiaDynamicMenu *ddm, gchar *string)
332 GtkWidget *item = gtk_menu_item_new_with_label(string);
333 if (strchr(string, '&')) {
334 gchar *escaped = replace_ampersands(string);
335 gchar *label = g_strdup_printf("<span face=\"%s\" size=\"medium\">%s</span>",
336 escaped, escaped);
337 gtk_label_set_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item))), label);
338 g_free(label);
339 g_free(escaped);
340 } else {
341 gchar *label = g_strdup_printf("<span face=\"%s\" size=\"medium\">%s</span>",
342 string, string);
343 gtk_label_set_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item))), label);
344 g_free(label);
346 return item;
349 static void
350 dia_font_selector_init (DiaFontSelector *fs)
352 GtkWidget *menu;
353 GtkWidget *omenu;
355 PangoFontFamily **families;
356 int n_families,i;
357 GList *fontnames = NULL;
359 pango_context_list_families (dia_font_get_context(),
360 &families, &n_families);
361 qsort(families, n_families, sizeof(PangoFontFamily*),
362 dia_font_selector_sort_fonts);
363 /* Doing it the slow way until I find a better way */
364 for (i = 0; i < n_families; i++) {
365 fontnames = g_list_append(fontnames,
366 g_strdup(pango_font_family_get_name(families[i])));
368 g_free (families);
370 fs->font_omenu =
371 GTK_OPTION_MENU
372 (dia_dynamic_menu_new_listbased(dia_font_selector_create_string_item,
373 dia_font_selector_fontmenu_callback,
375 _("Other fonts"),
376 fontnames,
377 "font-menu"));
378 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(fs->font_omenu),
379 "sans");
380 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(fs->font_omenu),
381 "serif");
382 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(fs->font_omenu),
383 "monospace");
384 gtk_widget_show(GTK_WIDGET(fs->font_omenu));
386 /* Now build the style menu button */
387 omenu = gtk_option_menu_new();
388 fs->style_omenu = GTK_OPTION_MENU(omenu);
389 menu = gtk_menu_new ();
390 fs->style_menu = GTK_MENU(menu);
391 gtk_option_menu_set_menu (GTK_OPTION_MENU (fs->style_omenu), menu);
393 gtk_widget_show(menu);
394 gtk_widget_show(omenu);
396 gtk_box_pack_start_defaults(GTK_BOX(fs), GTK_WIDGET(fs->font_omenu));
397 gtk_box_pack_start_defaults(GTK_BOX(fs), GTK_WIDGET(fs->style_omenu));
400 GtkType
401 dia_font_selector_get_type (void)
403 static GtkType dfs_type = 0;
405 if (!dfs_type) {
406 static const GtkTypeInfo dfs_info = {
407 "DiaFontSelector",
408 sizeof (DiaFontSelector),
409 sizeof (DiaFontSelectorClass),
410 (GtkClassInitFunc) dia_font_selector_class_init,
411 (GtkObjectInitFunc) dia_font_selector_init,
412 NULL,
413 NULL,
414 (GtkClassInitFunc) NULL
417 dfs_type = gtk_type_unique (gtk_hbox_get_type (), &dfs_info);
420 return dfs_type;
423 GtkWidget *
424 dia_font_selector_new ()
426 return GTK_WIDGET ( gtk_type_new (dia_font_selector_get_type ()));
429 static PangoFontFamily *
430 dia_font_selector_get_family_from_name(GtkWidget *widget, const gchar *fontname)
432 PangoFontFamily **families;
433 int n_families,i;
435 pango_context_list_families (dia_font_get_context(),
436 &families, &n_families);
437 /* Doing it the slow way until I find a better way */
438 for (i = 0; i < n_families; i++) {
439 if (!(g_strcasecmp(pango_font_family_get_name(families[i]), fontname))) {
440 PangoFontFamily *fam = families[i];
441 g_free(families);
442 return fam;
445 g_warning(_("Couldn't find font family for %s\n"), fontname);
446 g_free(families);
447 return NULL;
450 static void
451 dia_font_selector_fontmenu_callback(DiaDynamicMenu *ddm, const gchar *fontname, gpointer data)
453 DiaFontSelector *fs = DIAFONTSELECTOR(data);
454 dia_font_selector_set_styles(fs, fontname, -1);
457 static char *style_labels[] = {
458 "Normal",
459 "Oblique",
460 "Italic",
461 "Ultralight",
462 "Ultralight-Oblique",
463 "Ultralight-Italic",
464 "Light",
465 "Light-Oblique",
466 "Light-Italic",
467 "Medium",
468 "Medium-Oblique",
469 "Medium-Italic",
470 "Demibold",
471 "Demibold-Oblique",
472 "Demibold-Italic",
473 "Bold",
474 "Bold-Oblique",
475 "Bold-Italic",
476 "Ultrabold",
477 "Ultrabold-Oblique",
478 "Ultrabold-Italic",
479 "Heavy",
480 "Heavy-Oblique",
481 "Heavy-Italic"
484 static void
485 dia_font_selector_set_style_menu(DiaFontSelector *fs,
486 PangoFontFamily *pff,
487 DiaFontStyle dia_style)
489 int i=0, select = 0;
490 PangoFontFace **faces = NULL;
491 int nfaces = 0;
492 GtkWidget *menu = NULL;
493 long stylebits = 0;
494 int menu_item_nr = 0;
495 GSList *group = NULL;
497 menu = gtk_menu_new ();
498 pango_font_family_list_faces(pff, &faces, &nfaces);
500 for (i = 0; i < nfaces; i++) {
501 PangoFontDescription *pfd = pango_font_face_describe(faces[i]);
502 PangoStyle style = pango_font_description_get_style(pfd);
503 PangoWeight weight = pango_font_description_get_weight(pfd);
505 * This is a quick and dirty way to pick the styles present,
506 * sort them and avoid duplicates.
507 * We set a bit for each style present, bit (weight*3+style)
508 * From style_labels, we pick #(weight*3+style)
509 * where weight and style are the Dia types.
511 /* Account for DIA_WEIGHT_NORMAL hack */
512 int weightnr = (weight-200)/100;
513 if (weightnr < 2) weightnr ++;
514 else if (weightnr == 2) weightnr = 0;
515 stylebits |= 1 << (3*weightnr + style);
516 pango_font_description_free(pfd);
519 g_free(faces);
521 if (stylebits == 0) {
522 g_warning ("'%s' has no style!",
523 pango_font_family_get_name (pff) ? pango_font_family_get_name (pff) : "(null font)");
526 for (i = DIA_FONT_NORMAL; i <= (DIA_FONT_HEAVY | DIA_FONT_ITALIC); i+=4) {
527 GtkWidget *menuitem;
529 * bad hack continued ...
531 int weight = DIA_FONT_STYLE_GET_WEIGHT(i) >> 4;
532 int slant = DIA_FONT_STYLE_GET_SLANT(i) >> 2;
533 if (DIA_FONT_STYLE_GET_SLANT(i) > DIA_FONT_ITALIC) continue;
534 if (!(stylebits & (1 << (3*weight + slant)))) continue;
535 menuitem = gtk_radio_menu_item_new_with_label (group, style_labels[3*weight+slant]);
536 group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menuitem));
537 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(i));
538 if (dia_style == i) {
539 select = menu_item_nr;
541 menu_item_nr++;
542 gtk_menu_append (GTK_MENU (menu), menuitem);
543 gtk_widget_show (menuitem);
545 gtk_widget_show(menu);
546 gtk_option_menu_remove_menu(fs->style_omenu);
547 gtk_option_menu_set_menu(fs->style_omenu, menu);
548 fs->style_menu = GTK_MENU(menu);
549 gtk_option_menu_set_history(GTK_OPTION_MENU(fs->style_omenu), select);
550 gtk_menu_set_active(fs->style_menu, select);
551 gtk_widget_set_sensitive(GTK_WIDGET(fs->style_omenu), menu_item_nr > 1);
552 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_menu_get_active(fs->style_menu)), TRUE);
555 static void
556 dia_font_selector_set_styles(DiaFontSelector *fs,
557 const gchar *name, DiaFontStyle dia_style)
559 PangoFontFamily *pff;
560 pff = dia_font_selector_get_family_from_name(GTK_WIDGET(fs), name);
561 dia_font_selector_set_style_menu(fs, pff, dia_style);
565 /* API functions */
566 /** Set a string to be used for preview in the GTK font selector dialog.
567 * The start of this string will be copied.
568 * This function is now obsolete.
570 void
571 dia_font_selector_set_preview(DiaFontSelector *fs, gchar *text) {
574 /** Set the current font to be shown in the font selector.
576 void
577 dia_font_selector_set_font(DiaFontSelector *fs, DiaFont *font)
579 const gchar *fontname = dia_font_get_family(font);
580 /* side effect: adds fontname to presistence list */
581 dia_dynamic_menu_select_entry(DIA_DYNAMIC_MENU(fs->font_omenu), fontname);
582 dia_font_selector_set_styles(fs, fontname, dia_font_get_style (font));
585 DiaFont *
586 dia_font_selector_get_font(DiaFontSelector *fs)
588 GtkWidget *menuitem;
589 char *fontname;
590 DiaFontStyle style;
591 DiaFont *font;
593 fontname = dia_dynamic_menu_get_entry(DIA_DYNAMIC_MENU(fs->font_omenu));
594 menuitem = gtk_menu_get_active(fs->style_menu);
595 if (!menuitem) /* FIXME: should not happen ??? (but does if we don't have added a style) */
596 style = 0;
597 else
598 style = GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(menuitem)));
599 font = dia_font_new(fontname, style, 1.0);
600 g_free(fontname);
601 return font;
604 /************* DiaAlignmentSelector: ***************/
605 struct _DiaAlignmentSelector
607 GtkOptionMenu omenu;
609 GtkMenu *alignment_menu;
612 struct _DiaAlignmentSelectorClass
614 GtkOptionMenuClass parent_class;
617 static void
618 dia_alignment_selector_class_init (DiaAlignmentSelectorClass *class)
620 GtkObjectClass *object_class;
622 object_class = (GtkObjectClass*) class;
625 static void
626 dia_alignment_selector_init (DiaAlignmentSelector *fs)
628 GtkWidget *menu;
629 GtkWidget *submenu;
630 GtkWidget *menuitem;
631 GSList *group;
633 menu = gtk_menu_new ();
634 fs->alignment_menu = GTK_MENU(menu);
635 submenu = NULL;
636 group = NULL;
638 menuitem = gtk_radio_menu_item_new_with_label (group, _("Left"));
639 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(ALIGN_LEFT));
640 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
641 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
642 gtk_widget_show (menuitem);
644 menuitem = gtk_radio_menu_item_new_with_label (group, _("Center"));
645 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(ALIGN_CENTER));
646 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
647 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
648 gtk_widget_show (menuitem);
650 menuitem = gtk_radio_menu_item_new_with_label (group, _("Right"));
651 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(ALIGN_RIGHT));
652 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
653 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
654 gtk_widget_show (menuitem);
656 gtk_menu_set_active(GTK_MENU (menu), DEFAULT_ALIGNMENT);
657 gtk_option_menu_set_menu (GTK_OPTION_MENU (fs), menu);
660 GtkType
661 dia_alignment_selector_get_type (void)
663 static GtkType dfs_type = 0;
665 if (!dfs_type) {
666 static const GtkTypeInfo dfs_info = {
667 "DiaAlignmentSelector",
668 sizeof (DiaAlignmentSelector),
669 sizeof (DiaAlignmentSelectorClass),
670 (GtkClassInitFunc) dia_alignment_selector_class_init,
671 (GtkObjectInitFunc) dia_alignment_selector_init,
672 NULL,
673 NULL,
674 (GtkClassInitFunc) NULL,
677 dfs_type = gtk_type_unique (gtk_option_menu_get_type (), &dfs_info);
680 return dfs_type;
683 GtkWidget *
684 dia_alignment_selector_new ()
686 return GTK_WIDGET ( gtk_type_new (dia_alignment_selector_get_type ()));
690 Alignment
691 dia_alignment_selector_get_alignment(DiaAlignmentSelector *fs)
693 GtkWidget *menuitem;
694 void *align;
696 menuitem = gtk_menu_get_active(fs->alignment_menu);
697 align = gtk_object_get_user_data(GTK_OBJECT(menuitem));
699 return GPOINTER_TO_INT(align);
702 void
703 dia_alignment_selector_set_alignment (DiaAlignmentSelector *as,
704 Alignment align)
706 gtk_menu_set_active(GTK_MENU (as->alignment_menu), align);
707 gtk_option_menu_set_history (GTK_OPTION_MENU(as), align);
710 /************* DiaLineStyleSelector: ***************/
711 struct _DiaLineStyleSelector
713 GtkVBox vbox;
715 GtkOptionMenu *omenu;
716 GtkMenu *linestyle_menu;
717 GtkLabel *lengthlabel;
718 GtkSpinButton *dashlength;
722 struct _DiaLineStyleSelectorClass
724 GtkVBoxClass parent_class;
727 static void
728 dia_line_style_selector_class_init (DiaLineStyleSelectorClass *class)
730 GtkObjectClass *object_class;
732 object_class = (GtkObjectClass*) class;
735 static void
736 set_linestyle_sensitivity(DiaLineStyleSelector *fs)
738 int state;
739 GtkWidget *menuitem;
740 if (!fs->linestyle_menu) return;
741 menuitem = gtk_menu_get_active(fs->linestyle_menu);
742 state = (GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(menuitem)))
743 != LINESTYLE_SOLID);
745 gtk_widget_set_sensitive(GTK_WIDGET(fs->lengthlabel), state);
746 gtk_widget_set_sensitive(GTK_WIDGET(fs->dashlength), state);
749 static void
750 linestyle_type_change_callback(GtkObject *as, gboolean arg1, gpointer data)
752 set_linestyle_sensitivity(DIALINESTYLESELECTOR(as));
755 static void
756 dia_line_style_selector_init (DiaLineStyleSelector *fs)
758 GtkWidget *menu;
759 GtkWidget *submenu;
760 GtkWidget *menuitem, *ln;
761 GtkWidget *label;
762 GtkWidget *length;
763 GtkWidget *box;
764 GSList *group;
765 GtkAdjustment *adj;
766 gint i;
768 menu = gtk_option_menu_new();
769 fs->omenu = GTK_OPTION_MENU(menu);
771 menu = gtk_menu_new ();
772 fs->linestyle_menu = GTK_MENU(menu);
773 submenu = NULL;
774 group = NULL;
776 for (i = 0; i <= LINESTYLE_DOTTED; i++) {
777 menuitem = gtk_menu_item_new();
778 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(i));
779 ln = dia_line_preview_new(i);
780 gtk_container_add(GTK_CONTAINER(menuitem), ln);
781 gtk_widget_show(ln);
782 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
783 gtk_widget_show(menuitem);
785 #if 0
786 menuitem = gtk_radio_menu_item_new_with_label (group, _("Solid"));
787 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(LINESTYLE_SOLID));
788 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
789 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
790 gtk_widget_show (menuitem);
792 menuitem = gtk_radio_menu_item_new_with_label (group, _("Dashed"));
793 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(LINESTYLE_DASHED));
794 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
795 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
796 gtk_widget_show (menuitem);
798 menuitem = gtk_radio_menu_item_new_with_label (group, _("Dash-Dot"));
799 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(LINESTYLE_DASH_DOT));
800 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
801 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
802 gtk_widget_show (menuitem);
804 menuitem = gtk_radio_menu_item_new_with_label (group, _("Dash-Dot-Dot"));
805 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(LINESTYLE_DASH_DOT_DOT));
806 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
807 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
808 gtk_widget_show (menuitem);
810 menuitem = gtk_radio_menu_item_new_with_label (group, _("Dotted"));
811 gtk_object_set_user_data(GTK_OBJECT(menuitem), GINT_TO_POINTER(LINESTYLE_DOTTED));
812 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
813 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
814 gtk_widget_show (menuitem);
815 #endif
817 gtk_menu_set_active(GTK_MENU (menu), DEFAULT_LINESTYLE);
818 gtk_option_menu_set_menu (GTK_OPTION_MENU (fs->omenu), menu);
819 gtk_signal_connect_object(GTK_OBJECT(menu), "selection-done",
820 GTK_SIGNAL_FUNC(linestyle_type_change_callback),
821 (gpointer)fs);
823 gtk_box_pack_start(GTK_BOX(fs), GTK_WIDGET(fs->omenu), FALSE, TRUE, 0);
824 gtk_widget_show(GTK_WIDGET(fs->omenu));
826 box = gtk_hbox_new(FALSE,0);
827 /* fs->sizebox = GTK_HBOX(box); */
829 label = gtk_label_new(_("Dash length: "));
830 fs->lengthlabel = GTK_LABEL(label);
831 gtk_box_pack_start_defaults(GTK_BOX(box), label);
832 gtk_widget_show(label);
834 adj = (GtkAdjustment *)gtk_adjustment_new(0.1, 0.00, 10.0, 0.1, 1.0, 1.0);
835 length = gtk_spin_button_new(adj, DEFAULT_LINESTYLE_DASHLEN, 2);
836 gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(length), TRUE);
837 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(length), TRUE);
838 fs->dashlength = GTK_SPIN_BUTTON(length);
839 gtk_box_pack_start_defaults(GTK_BOX (box), length);
840 gtk_widget_show (length);
842 set_linestyle_sensitivity(fs);
843 gtk_box_pack_start_defaults(GTK_BOX(fs), box);
844 gtk_widget_show(box);
848 GtkType
849 dia_line_style_selector_get_type (void)
851 static GtkType dfs_type = 0;
853 if (!dfs_type) {
854 static const GtkTypeInfo dfs_info = {
855 "DiaLineStyleSelector",
856 sizeof (DiaLineStyleSelector),
857 sizeof (DiaLineStyleSelectorClass),
858 (GtkClassInitFunc) dia_line_style_selector_class_init,
859 (GtkObjectInitFunc) dia_line_style_selector_init,
860 NULL,
861 NULL,
862 (GtkClassInitFunc) NULL,
865 dfs_type = gtk_type_unique (gtk_vbox_get_type (), &dfs_info);
868 return dfs_type;
871 GtkWidget *
872 dia_line_style_selector_new ()
874 return GTK_WIDGET ( gtk_type_new (dia_line_style_selector_get_type ()));
878 void
879 dia_line_style_selector_get_linestyle(DiaLineStyleSelector *fs,
880 LineStyle *ls, real *dl)
882 GtkWidget *menuitem;
883 void *align;
885 menuitem = gtk_menu_get_active(fs->linestyle_menu);
886 align = gtk_object_get_user_data(GTK_OBJECT(menuitem));
887 *ls = GPOINTER_TO_INT(align);
888 if (dl!=NULL) {
889 *dl = gtk_spin_button_get_value(fs->dashlength);
893 void
894 dia_line_style_selector_set_linestyle (DiaLineStyleSelector *as,
895 LineStyle linestyle, real dashlength)
897 gtk_menu_set_active(GTK_MENU (as->linestyle_menu), linestyle);
898 gtk_option_menu_set_history (GTK_OPTION_MENU(as->omenu), linestyle);
899 /* TODO restore this later */
900 /* gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(gtk_menu_get_active(GTK_MENU(as->linestyle_menu))), TRUE);*/
901 set_linestyle_sensitivity(DIALINESTYLESELECTOR(as));
902 gtk_spin_button_set_value(GTK_SPIN_BUTTON(as->dashlength), dashlength);
907 /************* DiaColorSelector: ***************/
909 static GtkWidget *
910 dia_color_selector_create_string_item(DiaDynamicMenu *ddm, gchar *string)
912 GtkWidget *item = gtk_menu_item_new_with_label(string);
913 gint r, g, b;
914 sscanf(string, "#%2x%2x%2x", &r, &g, &b);
916 /* See http://web.umr.edu/~rhall/commentary/color_readability.htm for
917 * explanation of this formula */
918 if (r*299+g*587+b*114 > 500 * 256) {
919 gchar *label = g_strdup_printf("<span foreground=\"black\" background=\"%s\">%s</span>", string, string);
920 gtk_label_set_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item))), label);
921 g_free(label);
922 } else {
923 gchar *label = g_strdup_printf("<span foreground=\"white\" background=\"%s\">%s</span>", string, string);
924 gtk_label_set_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item))), label);
925 g_free(label);
928 return item;
931 static void
932 dia_color_selector_more_ok(GtkWidget *ok, gpointer userdata)
934 DiaDynamicMenu *ddm = g_object_get_data(G_OBJECT(userdata), "ddm");
935 GtkWidget *colorsel = GTK_WIDGET(userdata);
936 GdkColor gcol;
937 gchar *entry;
939 gtk_color_selection_get_current_color(
940 GTK_COLOR_SELECTION(
941 GTK_COLOR_SELECTION_DIALOG(colorsel)->colorsel),
942 &gcol);
944 entry = g_strdup_printf("#%02X%02X%02X", gcol.red/256, gcol.green/256, gcol.blue/256);
945 dia_dynamic_menu_select_entry(ddm, entry);
946 g_free(entry);
948 gtk_widget_destroy(colorsel);
951 static void
952 dia_color_selector_activate(DiaDynamicMenu *ddm, const gchar *entry, gpointer data)
956 static void
957 dia_color_selector_more_callback(GtkWidget *widget, gpointer userdata)
959 GtkColorSelectionDialog *dialog = GTK_COLOR_SELECTION_DIALOG (gtk_color_selection_dialog_new(_("Select color")));
960 DiaDynamicMenu *ddm = DIA_DYNAMIC_MENU(userdata);
961 GtkColorSelection *colorsel = GTK_COLOR_SELECTION(dialog->colorsel);
962 GString *palette = g_string_new ("");
964 gchar *old_color = dia_dynamic_menu_get_entry(ddm);
965 /* Force history to the old place */
966 dia_dynamic_menu_select_entry(ddm, old_color);
968 if (ddm->default_entries != NULL) {
969 GList *tmplist;
970 int index = 0;
971 gboolean advance = TRUE;
973 for (tmplist = ddm->default_entries;
974 tmplist != NULL || advance;
975 tmplist = g_list_next(tmplist)) {
976 const gchar* spec;
977 GdkColor color;
979 /* handle both lists */
980 if (!tmplist && advance) {
981 advance = FALSE;
982 tmplist = persistent_list_get_glist(ddm->persistent_name);
983 if (!tmplist)
984 break;
986 spec = (gchar *)tmplist->data;
988 gdk_color_parse (spec, &color);
989 #if 0
990 /* the easy way if the Gtk Team would decide to make it public */
991 gtk_color_selection_set_palette_color (colorsel, index, &color);
992 #else
993 g_string_append (palette, spec);
994 g_string_append (palette, ":");
995 #endif
996 if (0 == strcmp (spec, old_color)) {
997 gtk_color_selection_set_previous_color (colorsel, &color);
998 gtk_color_selection_set_current_color (colorsel, &color);
1000 index++;
1004 g_object_set (gtk_widget_get_settings (GTK_WIDGET (colorsel)), "gtk-color-palette", palette->str, NULL);
1005 gtk_color_selection_set_has_palette (colorsel, TRUE);
1006 g_string_free (palette, TRUE);
1007 g_free(old_color);
1009 gtk_widget_hide(dialog->help_button);
1011 gtk_signal_connect (GTK_OBJECT (dialog->ok_button), "clicked",
1012 (GtkSignalFunc) dia_color_selector_more_ok,
1013 dialog);
1014 gtk_signal_connect_object(GTK_OBJECT (dialog->cancel_button), "clicked",
1015 (GtkSignalFunc) gtk_widget_destroy,
1016 GTK_OBJECT(dialog));
1017 g_object_set_data(G_OBJECT(dialog), "ddm", ddm);
1019 gtk_widget_show(GTK_WIDGET(dialog));
1022 GtkWidget *
1023 dia_color_selector_new ()
1025 GtkWidget *otheritem = gtk_menu_item_new_with_label(_("More colors..."));
1026 GtkWidget *ddm = dia_dynamic_menu_new(dia_color_selector_create_string_item,
1027 dia_color_selector_activate,
1028 NULL,
1029 GTK_MENU_ITEM(otheritem),
1030 "color-menu");
1031 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(ddm),
1032 "#000000");
1033 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(ddm),
1034 "#FFFFFF");
1035 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(ddm),
1036 "#FF0000");
1037 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(ddm),
1038 "#00FF00");
1039 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(ddm),
1040 "#0000FF");
1041 g_signal_connect(G_OBJECT(otheritem), "activate",
1042 G_CALLBACK(dia_color_selector_more_callback), ddm);
1043 gtk_widget_show(otheritem);
1044 return ddm;
1048 void
1049 dia_color_selector_get_color(GtkWidget *widget, Color *color)
1051 gchar *entry = dia_dynamic_menu_get_entry(DIA_DYNAMIC_MENU(widget));
1052 gint r, g, b;
1054 sscanf(entry, "#%2x%2x%2x", &r, &g, &b);
1055 g_free(entry);
1056 color->red = r / 255.0;
1057 color->green = g / 255.0;
1058 color->blue = b / 255.0;
1061 void
1062 dia_color_selector_set_color (GtkWidget *widget,
1063 const Color *color)
1065 gint red, green, blue;
1066 gchar *entry;
1067 red = color->red * 255;
1068 green = color->green * 255;
1069 blue = color->blue * 255;
1070 if (color->red > 1.0 || color->green > 1.0 || color->blue > 1.0) {
1071 printf("Color out of range: r %f, g %f, b %f\n",
1072 color->red, color->green, color->blue);
1073 red = MIN(red, 255);
1074 green = MIN(green, 255);
1075 blue = MIN(blue, 255);
1077 entry = g_strdup_printf("#%02X%02X%02X", red, green, blue);
1078 dia_dynamic_menu_select_entry(DIA_DYNAMIC_MENU(widget), entry);
1079 g_free (entry);
1083 /************* DiaArrowSelector: ***************/
1084 struct _DiaArrowSelector
1086 GtkVBox vbox;
1088 GtkHBox *sizebox;
1089 GtkLabel *sizelabel;
1090 DiaSizeSelector *size;
1092 GtkOptionMenu *omenu;
1095 struct _DiaArrowSelectorClass
1097 GtkVBoxClass parent_class;
1100 static void
1101 dia_arrow_selector_class_init (DiaArrowSelectorClass *class)
1105 static void
1106 set_size_sensitivity(DiaArrowSelector *as)
1108 int state;
1109 gchar *entryname = dia_dynamic_menu_get_entry(DIA_DYNAMIC_MENU(as->omenu));
1111 state = (entryname != NULL) && (0 != g_strcasecmp(entryname, "None"));
1112 g_free(entryname);
1114 gtk_widget_set_sensitive(GTK_WIDGET(as->sizelabel), state);
1115 gtk_widget_set_sensitive(GTK_WIDGET(as->size), state);
1118 static void
1119 arrow_type_change_callback(DiaDynamicMenu *ddm, const gchar *name, gpointer userdata)
1121 set_size_sensitivity(DIA_ARROW_SELECTOR(userdata));
1124 static GtkWidget *
1125 create_arrow_menu_item(DiaDynamicMenu *ddm, gchar *name)
1127 ArrowType atype = arrow_type_from_name(name);
1128 GtkWidget *item = gtk_menu_item_new();
1129 GtkWidget *preview = dia_arrow_preview_new(atype, FALSE);
1131 gtk_widget_show(preview);
1132 gtk_container_add(GTK_CONTAINER(item), preview);
1133 gtk_widget_show(item);
1134 return item;
1137 static void
1138 dia_arrow_selector_init (DiaArrowSelector *as,
1139 gpointer g_class)
1141 GtkWidget *omenu;
1142 GtkWidget *box;
1143 GtkWidget *label;
1144 GtkWidget *size;
1146 GList *arrow_names = get_arrow_names();
1147 omenu = dia_dynamic_menu_new_listbased(create_arrow_menu_item,
1148 arrow_type_change_callback, as,
1149 _("More arrows"),
1150 arrow_names,
1151 "arrow-menu");
1152 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(omenu), "None");
1153 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(omenu), "Lines");
1154 dia_dynamic_menu_add_default_entry(DIA_DYNAMIC_MENU(omenu), "Filled Concave");
1155 as->omenu = GTK_OPTION_MENU(omenu);
1156 gtk_box_pack_start(GTK_BOX(as), omenu, FALSE, TRUE, 0);
1157 gtk_widget_show(omenu);
1159 box = gtk_hbox_new(FALSE,0);
1160 as->sizebox = GTK_HBOX(box);
1162 label = gtk_label_new(_("Size: "));
1163 as->sizelabel = GTK_LABEL(label);
1164 gtk_box_pack_start_defaults(GTK_BOX(box), label);
1165 gtk_widget_show(label);
1167 size = dia_size_selector_new(0.0, 0.0);
1168 as->size = DIA_SIZE_SELECTOR(size);
1169 gtk_box_pack_start_defaults(GTK_BOX(box), size);
1170 gtk_widget_show(size);
1172 set_size_sensitivity(as);
1173 gtk_box_pack_start_defaults(GTK_BOX(as), box);
1175 gtk_widget_show(box);
1179 GType
1180 dia_arrow_selector_get_type (void)
1182 static GType dfs_type = 0;
1184 if (!dfs_type) {
1185 static const GTypeInfo dfs_info = {
1186 /* sizeof (DiaArrowSelector),*/
1187 sizeof (DiaArrowSelectorClass),
1188 (GBaseInitFunc) NULL,
1189 (GBaseFinalizeFunc) NULL,
1190 (GClassInitFunc) dia_arrow_selector_class_init,
1191 NULL, /* class_finalize */
1192 NULL, /* class_data */
1193 sizeof (DiaArrowSelector),
1194 0, /* n_preallocs */
1195 (GInstanceInitFunc)dia_arrow_selector_init, /* init */
1197 (GtkObjectInitFunc) dia_arrow_selector_init,
1198 NULL,
1199 NULL,
1200 (GtkClassInitFunc) NULL,
1204 dfs_type = g_type_register_static (GTK_TYPE_VBOX,
1205 "DiaArrowSelector",
1206 &dfs_info, 0);
1209 return dfs_type;
1212 GtkWidget *
1213 dia_arrow_selector_new ()
1215 return GTK_WIDGET ( g_object_new (DIA_TYPE_ARROW_SELECTOR, NULL));
1219 Arrow
1220 dia_arrow_selector_get_arrow(DiaArrowSelector *as)
1222 Arrow at;
1223 gchar *arrowname = dia_dynamic_menu_get_entry(DIA_DYNAMIC_MENU(as->omenu));
1225 at.type = arrow_type_from_name(arrowname);
1226 g_free(arrowname);
1227 dia_size_selector_get_size(as->size, &at.width, &at.length);
1228 return at;
1231 void
1232 dia_arrow_selector_set_arrow (DiaArrowSelector *as,
1233 Arrow arrow)
1235 dia_dynamic_menu_select_entry(DIA_DYNAMIC_MENU(as->omenu),
1236 arrow_types[arrow_index_from_type(arrow.type)].name);
1237 set_size_sensitivity(as);
1238 dia_size_selector_set_size(DIA_SIZE_SELECTOR(as->size), arrow.width, arrow.length);
1241 /************* DiaFileSelector: ***************/
1242 struct _DiaFileSelector
1244 GtkHBox hbox;
1245 GtkEntry *entry;
1246 GtkButton *browse;
1247 GtkFileSelection *dialog;
1248 gchar *sys_filename;
1251 struct _DiaFileSelectorClass
1253 GtkHBoxClass parent_class;
1256 static void
1257 dia_file_selector_unrealize(GtkWidget *widget)
1259 DiaFileSelector *fs = DIAFILESELECTOR(widget);
1261 if (fs->dialog != NULL) {
1262 gtk_widget_destroy(GTK_WIDGET(fs->dialog));
1263 fs->dialog = NULL;
1265 if (fs->sys_filename) {
1266 g_free(fs->sys_filename);
1267 fs->sys_filename = NULL;
1270 (* GTK_WIDGET_CLASS (gtk_type_class(gtk_hbox_get_type ()))->unrealize) (widget);
1273 static void
1274 dia_file_selector_class_init (DiaFileSelectorClass *class)
1276 GtkObjectClass *object_class;
1277 GtkWidgetClass *widget_class;
1279 object_class = (GtkObjectClass*) class;
1280 widget_class = (GtkWidgetClass*) class;
1281 widget_class->unrealize = dia_file_selector_unrealize;
1284 static void
1285 dia_file_selector_ok(GtkWidget *widget, gpointer data)
1287 gchar *utf8;
1288 GtkFileSelection *dialog = GTK_FILE_SELECTION(data);
1289 DiaFileSelector *fs =
1290 DIAFILESELECTOR(gtk_object_get_user_data(GTK_OBJECT(dialog)));
1291 utf8 = g_filename_to_utf8(gtk_file_selection_get_filename(dialog),
1292 -1, NULL, NULL, NULL);
1293 gtk_entry_set_text(GTK_ENTRY(fs->entry), utf8);
1294 g_free(utf8);
1295 gtk_widget_hide(GTK_WIDGET(dialog));
1298 static void
1299 dia_file_selector_browse_pressed(GtkWidget *widget, gpointer data)
1301 GtkFileSelection *dialog;
1302 DiaFileSelector *fs = DIAFILESELECTOR(data);
1303 gchar *filename;
1305 if (fs->dialog == NULL) {
1306 dialog = fs->dialog =
1307 GTK_FILE_SELECTION(gtk_file_selection_new(_("Select image file")));
1309 if (dialog->help_button != NULL)
1310 gtk_widget_hide(dialog->help_button);
1312 gtk_signal_connect (GTK_OBJECT (dialog->ok_button), "clicked",
1313 (GtkSignalFunc) dia_file_selector_ok,
1314 dialog);
1316 gtk_signal_connect (GTK_OBJECT (fs->dialog), "destroy",
1317 GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1318 &fs->dialog);
1320 gtk_signal_connect_object(GTK_OBJECT (dialog->cancel_button), "clicked",
1321 (GtkSignalFunc) gtk_widget_hide,
1322 GTK_OBJECT(dialog));
1324 gtk_object_set_user_data(GTK_OBJECT(dialog), fs);
1327 filename = g_filename_from_utf8(gtk_entry_get_text(fs->entry), -1, NULL, NULL, NULL);
1328 gtk_file_selection_set_filename(fs->dialog, filename);
1329 g_free(filename);
1331 gtk_widget_show(GTK_WIDGET(fs->dialog));
1334 static void
1335 dia_file_selector_init (DiaFileSelector *fs)
1337 /* Here's where we set up the real thing */
1338 fs->dialog = NULL;
1339 fs->sys_filename = NULL;
1340 fs->entry = GTK_ENTRY(gtk_entry_new());
1341 gtk_box_pack_start(GTK_BOX(fs), GTK_WIDGET(fs->entry), FALSE, TRUE, 0);
1342 gtk_widget_show(GTK_WIDGET(fs->entry));
1343 fs->browse = GTK_BUTTON(gtk_button_new_with_label(_("Browse")));
1344 gtk_box_pack_start(GTK_BOX(fs), GTK_WIDGET(fs->browse), FALSE, TRUE, 0);
1345 gtk_signal_connect (GTK_OBJECT (fs->browse), "clicked",
1346 (GtkSignalFunc) dia_file_selector_browse_pressed,
1347 fs);
1348 gtk_widget_show(GTK_WIDGET(fs->browse));
1352 GtkType
1353 dia_file_selector_get_type (void)
1355 static GtkType dfs_type = 0;
1357 if (!dfs_type) {
1358 static const GtkTypeInfo dfs_info = {
1359 "DiaFileSelector",
1360 sizeof (DiaFileSelector),
1361 sizeof (DiaFileSelectorClass),
1362 (GtkClassInitFunc) dia_file_selector_class_init,
1363 (GtkObjectInitFunc) dia_file_selector_init,
1364 NULL,
1365 NULL,
1366 (GtkClassInitFunc) NULL,
1369 dfs_type = gtk_type_unique (gtk_hbox_get_type (), &dfs_info);
1373 return dfs_type;
1376 GtkWidget *
1377 dia_file_selector_new ()
1379 return GTK_WIDGET ( gtk_type_new (dia_file_selector_get_type ()));
1382 void
1383 dia_file_selector_set_file(DiaFileSelector *fs, gchar *file)
1385 /* filename is in system encoding */
1386 gchar *utf8 = g_filename_to_utf8(file, -1, NULL, NULL, NULL);
1387 gtk_entry_set_text(GTK_ENTRY(fs->entry), utf8);
1388 g_free(utf8);
1391 const gchar *
1392 dia_file_selector_get_file(DiaFileSelector *fs)
1394 /* let it behave like gtk_file_selector_get_file */
1395 g_free(fs->sys_filename);
1396 fs->sys_filename = g_filename_from_utf8(gtk_entry_get_text(GTK_ENTRY(fs->entry)),
1397 -1, NULL, NULL, NULL);
1398 return fs->sys_filename;
1401 /************* DiaUnitSpinner: ***************/
1403 /** A Spinner that allows a 'favored' unit to display in. External access
1404 * to the value still happens in cm, but display is in the favored unit.
1405 * Internally, the value is kept in the favored unit to a) allow proper
1406 * limits, and b) avoid rounding problems while editing.
1409 typedef struct _DiaUnitDef DiaUnitDef;
1410 struct _DiaUnitDef {
1411 char* name;
1412 char* unit;
1413 float factor;
1416 /* from gnome-libs/libgnome/gnome-paper.c */
1417 static const DiaUnitDef units[] =
1419 /* XXX does anyone *really* measure paper size in feet? meters? */
1421 /* human name, abreviation, points per unit */
1422 { "Feet", "ft", 864 },
1423 { "Meter", "m", 2834.6457 },
1424 { "Decimeter", "dm", 283.46457 },
1425 { "Millimeter", "mm", 2.8346457 },
1426 { "Point", "pt", 1. },
1427 { "Centimeter", "cm", 28.346457 },
1428 { "Inch", "in", 72 },
1429 { "Pica", "pi", 12 },
1430 { 0 }
1433 static GtkObjectClass *parent_class;
1434 static GtkObjectClass *entry_class;
1436 static void dia_unit_spinner_class_init(DiaUnitSpinnerClass *class);
1437 static void dia_unit_spinner_init(DiaUnitSpinner *self);
1439 GtkType
1440 dia_unit_spinner_get_type(void)
1442 static GtkType us_type = 0;
1444 if (!us_type) {
1445 static const GtkTypeInfo us_info = {
1446 "DiaUnitSpinner",
1447 sizeof(DiaUnitSpinner),
1448 sizeof(DiaUnitSpinnerClass),
1449 (GtkClassInitFunc) dia_unit_spinner_class_init,
1450 (GtkObjectInitFunc) dia_unit_spinner_init,
1451 NULL,
1452 NULL,
1453 (GtkClassInitFunc) NULL,
1455 us_type = gtk_type_unique(gtk_spin_button_get_type(), &us_info);
1457 return us_type;
1460 /** Updates the spinner display to show digits and units */
1461 static void
1462 dia_unit_spinner_value_changed(GtkAdjustment *adjustment,
1463 DiaUnitSpinner *spinner)
1465 char buf[256];
1466 GtkSpinButton *sbutton = GTK_SPIN_BUTTON(spinner);
1468 g_snprintf(buf, sizeof(buf), "%0.*f%s", sbutton->digits, adjustment->value,
1469 units[spinner->unit_num].unit);
1470 gtk_entry_set_text(GTK_ENTRY(spinner), buf);
1473 static void dia_unit_spinner_set_value_direct(DiaUnitSpinner *self, gfloat val);
1474 static gint dia_unit_spinner_focus_out(GtkWidget *widget, GdkEventFocus *ev);
1475 static gint dia_unit_spinner_button_press(GtkWidget *widget,GdkEventButton*ev);
1476 static gint dia_unit_spinner_key_press(GtkWidget *widget, GdkEventKey *event);
1477 static void dia_unit_spinner_activate(GtkEntry *editable);
1479 static void
1480 dia_unit_spinner_class_init(DiaUnitSpinnerClass *class)
1482 GtkObjectClass *object_class;
1483 GtkWidgetClass *widget_class;
1484 GtkEntryClass *editable_class;
1486 object_class = (GtkObjectClass *)class;
1487 widget_class = (GtkWidgetClass *)class;
1488 editable_class = (GtkEntryClass *)class;
1490 widget_class->focus_out_event = dia_unit_spinner_focus_out;
1491 widget_class->button_press_event = dia_unit_spinner_button_press;
1492 widget_class->key_press_event = dia_unit_spinner_key_press;
1493 editable_class->activate = dia_unit_spinner_activate;
1495 parent_class = gtk_type_class(GTK_TYPE_SPIN_BUTTON);
1496 entry_class = gtk_type_class(GTK_TYPE_ENTRY);
1499 static void
1500 dia_unit_spinner_init(DiaUnitSpinner *self)
1502 /* change over to our own print function that appends the unit name on the
1503 * end */
1504 if (self->parent.adjustment) {
1505 gtk_signal_disconnect_by_data(GTK_OBJECT(self->parent.adjustment),
1506 (gpointer) self);
1507 g_signal_connect(GTK_OBJECT(self->parent.adjustment), "value_changed",
1508 G_CALLBACK(dia_unit_spinner_value_changed),
1509 (gpointer) self);
1512 self->unit_num = DIA_UNIT_CENTIMETER;
1515 GtkWidget *
1516 dia_unit_spinner_new(GtkAdjustment *adjustment, guint digits, DiaUnit adj_unit)
1518 DiaUnitSpinner *self = gtk_type_new(dia_unit_spinner_get_type());
1520 self->unit_num = adj_unit;
1522 gtk_spin_button_configure(GTK_SPIN_BUTTON(self), adjustment, 0.0, digits);
1524 if (adjustment) {
1525 gtk_signal_disconnect_by_data(GTK_OBJECT(adjustment),
1526 (gpointer) self);
1527 g_signal_connect(GTK_OBJECT(adjustment), "value_changed",
1528 G_CALLBACK(dia_unit_spinner_value_changed),
1529 (gpointer) self);
1530 dia_unit_spinner_set_value(self, adjustment->value);
1531 } else {
1532 /* Don't know any better, hopefully it'll be set later. */
1533 dia_unit_spinner_set_value(self, 1.0);
1536 return GTK_WIDGET(self);
1539 /** Set the value (in cm).
1540 * */
1541 void
1542 dia_unit_spinner_set_value(DiaUnitSpinner *self, gfloat val)
1544 dia_unit_spinner_set_value_direct(self, val /
1545 (units[self->unit_num].factor / units[DIA_UNIT_CENTIMETER].factor));
1548 /** Set the value (in preferred units) */
1549 static void
1550 dia_unit_spinner_set_value_direct(DiaUnitSpinner *self, gfloat val)
1552 GtkSpinButton *sbutton = GTK_SPIN_BUTTON(self);
1554 if (val < sbutton->adjustment->lower)
1555 val = sbutton->adjustment->lower;
1556 else if (val > sbutton->adjustment->upper)
1557 val = sbutton->adjustment->upper;
1558 sbutton->adjustment->value = val;
1559 dia_unit_spinner_value_changed(sbutton->adjustment, self);
1562 /** Get the value (in cm) */
1563 gfloat
1564 dia_unit_spinner_get_value(DiaUnitSpinner *self)
1566 GtkSpinButton *sbutton = GTK_SPIN_BUTTON(self);
1568 return sbutton->adjustment->value *
1569 (units[self->unit_num].factor / units[DIA_UNIT_CENTIMETER].factor);
1572 static void
1573 dia_unit_spinner_update(DiaUnitSpinner *self)
1575 gfloat val, factor = 1.0;
1576 gchar *extra = NULL;
1578 val = g_strtod(gtk_entry_get_text(GTK_ENTRY(self)), &extra);
1580 /* get rid of extra white space after number */
1581 while (*extra && g_ascii_isspace(*extra)) extra++;
1582 if (*extra) {
1583 int i;
1585 for (i = 0; units[i].name != NULL; i++)
1586 if (!g_strcasecmp(units[i].unit, extra)) {
1587 factor = units[i].factor / units[self->unit_num].factor;
1588 break;
1591 /* convert to prefered units */
1592 val *= factor;
1593 dia_unit_spinner_set_value_direct(self, val);
1596 static gint
1597 dia_unit_spinner_focus_out(GtkWidget *widget, GdkEventFocus *event)
1599 if (GTK_ENTRY (widget)->editable)
1600 dia_unit_spinner_update(DIA_UNIT_SPINNER(widget));
1601 return GTK_WIDGET_CLASS(entry_class)->focus_out_event(widget, event);
1604 static gint
1605 dia_unit_spinner_button_press(GtkWidget *widget, GdkEventButton *event)
1607 dia_unit_spinner_update(DIA_UNIT_SPINNER(widget));
1608 return GTK_WIDGET_CLASS(parent_class)->button_press_event(widget, event);
1611 static gint
1612 dia_unit_spinner_key_press(GtkWidget *widget, GdkEventKey *event)
1614 gint key = event->keyval;
1616 if (GTK_ENTRY (widget)->editable &&
1617 (key == GDK_Up || key == GDK_Down ||
1618 key == GDK_Page_Up || key == GDK_Page_Down))
1619 dia_unit_spinner_update (DIA_UNIT_SPINNER(widget));
1620 return GTK_WIDGET_CLASS(parent_class)->key_press_event(widget, event);
1623 static void
1624 dia_unit_spinner_activate(GtkEntry *editable)
1626 if (editable->editable)
1627 dia_unit_spinner_update(DIA_UNIT_SPINNER(editable));
1631 /* ************************ Dynamic menus ************************ */
1633 static void dia_dynamic_menu_class_init(DiaDynamicMenuClass *class);
1634 static void dia_dynamic_menu_init(DiaDynamicMenu *self);
1635 static void dia_dynamic_menu_create_sublist(DiaDynamicMenu *ddm,
1636 GList *items,
1637 DDMCreateItemFunc create);
1638 static void dia_dynamic_menu_create_menu(DiaDynamicMenu *ddm);
1639 static void dia_dynamic_menu_destroy(GtkObject *object);
1641 GtkType
1642 dia_dynamic_menu_get_type(void)
1644 static GtkType us_type = 0;
1646 if (!us_type) {
1647 static const GtkTypeInfo us_info = {
1648 "DiaDynamicMenu",
1649 sizeof(DiaDynamicMenu),
1650 sizeof(DiaDynamicMenuClass),
1651 (GtkClassInitFunc) dia_dynamic_menu_class_init,
1652 (GtkObjectInitFunc) dia_dynamic_menu_init,
1653 NULL,
1654 NULL,
1655 (GtkClassInitFunc) NULL,
1657 us_type = gtk_type_unique(gtk_option_menu_get_type(), &us_info);
1659 return us_type;
1662 static void
1663 dia_dynamic_menu_class_init(DiaDynamicMenuClass *class)
1665 GtkObjectClass *object_class = (GtkObjectClass*)class;
1667 object_class->destroy = dia_dynamic_menu_destroy;
1670 static void
1671 dia_dynamic_menu_init(DiaDynamicMenu *self)
1675 void
1676 dia_dynamic_menu_destroy(GtkObject *object)
1678 DiaDynamicMenu *ddm = DIA_DYNAMIC_MENU(object);
1679 GtkObjectClass *parent_class = GTK_OBJECT_CLASS(g_type_class_peek_parent(GTK_OBJECT_GET_CLASS(object)));
1681 if (ddm->active)
1682 g_free(ddm->active);
1683 ddm->active = NULL;
1685 if (parent_class->destroy)
1686 (* parent_class->destroy) (object);
1689 /** Create a new dynamic menu. The entries are represented with
1690 * gpointers.
1691 * @param create A function that creates menuitems from gpointers.
1692 * @param otheritem A menuitem that can be selected by the user to
1693 * add more entries, for instance making a dialog box or a submenu.
1694 * @param persist A string naming this menu for persistence purposes, or NULL.
1696 * @return A new menu
1698 GtkWidget *
1699 dia_dynamic_menu_new(DDMCreateItemFunc create,
1700 DDMCallbackFunc activate, gpointer userdata,
1701 GtkMenuItem *otheritem, gchar *persist)
1703 DiaDynamicMenu *ddm;
1705 g_assert(persist != NULL);
1707 ddm = DIA_DYNAMIC_MENU ( gtk_type_new (dia_dynamic_menu_get_type ()));
1709 ddm->create_func = create;
1710 ddm->activate_func = activate;
1711 ddm->userdata = userdata;
1712 ddm->other_item = otheritem;
1713 ddm->persistent_name = persist;
1714 ddm->cols = 1;
1716 persistence_register_list(persist);
1718 dia_dynamic_menu_create_menu(ddm);
1720 return GTK_WIDGET(ddm);
1723 /** Select the given entry, adding it if necessary */
1724 void
1725 dia_dynamic_menu_select_entry(DiaDynamicMenu *ddm, const gchar *name)
1727 gint add_result = dia_dynamic_menu_add_entry(ddm, name);
1728 if (add_result == 0) {
1729 GList *tmp;
1730 int i = 0;
1731 for (tmp = ddm->default_entries; tmp != NULL;
1732 tmp = g_list_next(tmp), i++) {
1733 if (!g_strcasecmp(tmp->data, name))
1734 gtk_option_menu_set_history(GTK_OPTION_MENU(ddm), i);
1736 /* Not there after all? */
1737 } else {
1738 if (ddm->default_entries != NULL)
1739 gtk_option_menu_set_history(GTK_OPTION_MENU(ddm),
1740 g_list_length(ddm->default_entries)+1);
1741 else
1742 gtk_option_menu_set_history(GTK_OPTION_MENU(ddm), 0);
1744 if (ddm->activate_func != NULL) {
1745 (ddm->activate_func)(ddm, name, ddm->userdata);
1749 static void
1750 dia_dynamic_menu_activate(GtkWidget *item, gpointer userdata)
1752 DiaDynamicMenu *ddm = DIA_DYNAMIC_MENU(userdata);
1753 gchar *name = g_object_get_data(G_OBJECT(item), "ddm_name");
1754 dia_dynamic_menu_select_entry(ddm, name);
1757 static GtkWidget *
1758 dia_dynamic_menu_create_string_item(DiaDynamicMenu *ddm, gchar *string)
1760 GtkWidget *item = gtk_menu_item_new_with_label(string);
1761 return item;
1764 /** Utility function for dynamic menus that are entirely based on the
1765 * labels in the menu.
1767 GtkWidget *
1768 dia_dynamic_menu_new_stringbased(GtkMenuItem *otheritem,
1769 DDMCallbackFunc activate,
1770 gpointer userdata,
1771 gchar *persist)
1773 GtkWidget *ddm = dia_dynamic_menu_new(dia_dynamic_menu_create_string_item,
1774 activate, userdata,
1775 otheritem, persist);
1776 return ddm;
1779 /** Utility function for dynamic menus that are based on a submenu with
1780 * many entries. This is useful for allowing the user to get a smaller
1781 * subset menu out of a set too large to be easily handled by a menu.
1783 GtkWidget *
1784 dia_dynamic_menu_new_listbased(DDMCreateItemFunc create,
1785 DDMCallbackFunc activate,
1786 gpointer userdata,
1787 gchar *other_label, GList *items,
1788 gchar *persist)
1790 GtkWidget *item = gtk_menu_item_new_with_label(other_label);
1791 GtkWidget *ddm = dia_dynamic_menu_new(create, activate, userdata,
1792 GTK_MENU_ITEM(item), persist);
1793 dia_dynamic_menu_create_sublist(DIA_DYNAMIC_MENU(ddm), items, create);
1795 gtk_widget_show(item);
1796 return ddm;
1799 /** Utility function for dynamic menus that allow selection from a large
1800 * number of strings.
1802 GtkWidget *
1803 dia_dynamic_menu_new_stringlistbased(gchar *other_label,
1804 GList *items,
1805 DDMCallbackFunc activate,
1806 gpointer userdata,
1807 gchar *persist)
1809 return dia_dynamic_menu_new_listbased(dia_dynamic_menu_create_string_item,
1810 activate, userdata,
1811 other_label, items, persist);
1814 static void
1815 dia_dynamic_menu_create_sublist(DiaDynamicMenu *ddm,
1816 GList *items, DDMCreateItemFunc create)
1818 GtkWidget *item = GTK_WIDGET(ddm->other_item);
1820 GtkWidget *submenu = gtk_menu_new();
1822 for (; items != NULL; items = g_list_next(items)) {
1823 GtkWidget *submenuitem = (create)(ddm, items->data);
1824 /* Set callback function to cause addition of item */
1825 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), submenuitem);
1826 g_object_set_data(G_OBJECT(submenuitem), "ddm_name", items->data);
1827 g_signal_connect(submenuitem, "activate",
1828 G_CALLBACK(dia_dynamic_menu_activate), ddm);
1829 gtk_widget_show(submenuitem);
1832 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
1833 gtk_widget_show(submenu);
1836 /** Add a new default entry to this menu.
1837 * The default entries are always shown, also after resets, above the
1838 * other entries. Possible uses are standard fonts or common colors.
1839 * The entry is added at the end of the default entries section.
1840 * Do not add too many default entries.
1842 * @param ddm A dynamic menu to add the entry to.
1843 * @param entry An entry for the menu.
1845 void
1846 dia_dynamic_menu_add_default_entry(DiaDynamicMenu *ddm, const gchar *entry)
1848 ddm->default_entries = g_list_append(ddm->default_entries, g_strdup(entry));
1850 dia_dynamic_menu_create_menu(ddm);
1853 /** Set the number of columns this menu uses (default 1)
1854 * @param cols Desired # of columns (>= 1)
1856 void
1857 dia_dynamic_menu_set_columns(DiaDynamicMenu *ddm, gint cols)
1859 ddm->cols = cols;
1861 dia_dynamic_menu_create_menu(ddm);
1864 /** Add a new entry to this menu. The placement depends on what sorting
1865 * system has been chosen with dia_dynamic_menu_set_sorting_method().
1867 * @param ddm A dynamic menu to add the entry to.
1868 * @param entry An entry for the menu.
1870 * @returns 0 if the entry was one of the default entries.
1871 * 1 if the entry was already there.
1872 * 2 if the entry got added.
1874 gint
1875 dia_dynamic_menu_add_entry(DiaDynamicMenu *ddm, const gchar *entry)
1877 GList *tmp;
1878 gboolean existed;
1880 g_free(ddm->active);
1881 ddm->active = g_strdup(entry);
1883 for (tmp = ddm->default_entries; tmp != NULL; tmp = g_list_next(tmp)) {
1884 if (!g_strcasecmp(tmp->data, entry))
1885 return 0;
1887 existed = persistent_list_add(ddm->persistent_name, entry);
1889 dia_dynamic_menu_create_menu(ddm);
1891 return existed?1:2;
1894 /** Returns the currently selected entry.
1895 * @returns The name of the entry that is currently selected. This
1896 * string should be freed by the caller. */
1897 gchar *
1898 dia_dynamic_menu_get_entry(DiaDynamicMenu *ddm)
1900 return g_strdup(ddm->active);
1903 /** Rebuild the actual menu of a DDM.
1904 * Ignores columns for now.
1906 static void
1907 dia_dynamic_menu_create_menu(DiaDynamicMenu *ddm)
1909 GtkWidget *sep;
1910 GList *tmplist;
1911 GtkWidget *menu;
1912 GtkWidget *item;
1914 g_object_ref(G_OBJECT(ddm->other_item));
1915 menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(ddm));
1916 if (menu != NULL) {
1917 gtk_container_remove(GTK_CONTAINER(menu), GTK_WIDGET(ddm->other_item));
1918 gtk_container_foreach(GTK_CONTAINER(menu),
1919 (GtkCallback)gtk_widget_destroy, NULL);
1920 gtk_option_menu_remove_menu(GTK_OPTION_MENU(ddm));
1923 menu = gtk_menu_new();
1925 if (ddm->default_entries != NULL) {
1926 for (tmplist = ddm->default_entries; tmplist != NULL; tmplist = g_list_next(tmplist)) {
1927 GtkWidget *item = (ddm->create_func)(ddm, tmplist->data);
1928 g_object_set_data(G_OBJECT(item), "ddm_name", tmplist->data);
1929 g_signal_connect(G_OBJECT(item), "activate",
1930 G_CALLBACK(dia_dynamic_menu_activate), ddm);
1931 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1932 gtk_widget_show(item);
1934 sep = gtk_separator_menu_item_new();
1935 gtk_widget_show(sep);
1936 gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
1939 for (tmplist = persistent_list_get_glist(ddm->persistent_name);
1940 tmplist != NULL; tmplist = g_list_next(tmplist)) {
1941 GtkWidget *item = (ddm->create_func)(ddm, tmplist->data);
1942 g_object_set_data(G_OBJECT(item), "ddm_name", tmplist->data);
1943 g_signal_connect(G_OBJECT(item), "activate",
1944 G_CALLBACK(dia_dynamic_menu_activate), ddm);
1945 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1946 gtk_widget_show(item);
1948 sep = gtk_separator_menu_item_new();
1949 gtk_widget_show(sep);
1950 gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
1952 gtk_menu_shell_append(GTK_MENU_SHELL(menu), GTK_WIDGET(ddm->other_item));
1953 g_object_unref(G_OBJECT(ddm->other_item));
1954 /* Eventually reset item here */
1955 gtk_widget_show(menu);
1957 item = gtk_menu_item_new_with_label(_("Reset menu"));
1958 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1959 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(dia_dynamic_menu_reset), ddm);
1960 gtk_widget_show(item);
1962 gtk_option_menu_set_menu(GTK_OPTION_MENU(ddm), menu);
1964 gtk_option_menu_set_history(GTK_OPTION_MENU(ddm), 0);
1967 /** Select the method used for sorting the non-default entries.
1968 * @param ddm A dynamic menu
1969 * @param sort The way the non-default entries in the menu should be sorted.
1971 void
1972 dia_dynamic_menu_set_sorting_method(DiaDynamicMenu *ddm, DdmSortType sort)
1976 /** Reset the non-default entries of a menu
1978 void
1979 dia_dynamic_menu_reset(GtkWidget *item, gpointer userdata)
1981 DiaDynamicMenu *ddm = DIA_DYNAMIC_MENU(userdata);
1982 PersistentList *plist = persistent_list_get(ddm->persistent_name);
1983 g_list_foreach(plist->glist, (GFunc)g_free, NULL);
1984 g_list_free(plist->glist);
1985 plist->glist = NULL;
1986 dia_dynamic_menu_create_menu(ddm);
1987 dia_dynamic_menu_select_entry(ddm, ddm->active);
1990 /** Set the maximum number of non-default entries.
1991 * If more than this number of entries are added, the least recently
1992 * selected ones are removed. */
1993 void
1994 dia_dynamic_menu_set_max_entries(DiaDynamicMenu *ddm, gint max)
1999 /* ************************ Misc. util functions ************************ */
2000 struct image_pair { GtkWidget *on; GtkWidget *off; };
2002 static void
2003 dia_toggle_button_swap_images(GtkToggleButton *widget,
2004 gpointer data)
2006 struct image_pair *images = (struct image_pair *)data;
2007 if (gtk_toggle_button_get_active(widget)) {
2008 gtk_container_remove(GTK_CONTAINER(widget),
2009 gtk_bin_get_child(GTK_BIN(widget)));
2010 gtk_container_add(GTK_CONTAINER(widget),
2011 images->on);
2013 } else {
2014 gtk_container_remove(GTK_CONTAINER(widget),
2015 gtk_bin_get_child(GTK_BIN(widget)));
2016 gtk_container_add(GTK_CONTAINER(widget),
2017 images->off);
2021 static void
2022 dia_toggle_button_destroy(GtkWidget *widget, gpointer data)
2024 struct image_pair *images = (struct image_pair *)data;
2026 if (images->on)
2027 g_object_unref(images->on);
2028 images->on = NULL;
2029 if (images->off)
2030 g_object_unref(images->off);
2031 images->off = NULL;
2032 if (images)
2033 g_free(images);
2034 images = NULL;
2037 /** Create a toggle button given two image widgets for on and off */
2038 static GtkWidget *
2039 dia_toggle_button_new(GtkWidget *on_widget, GtkWidget *off_widget)
2041 GtkWidget *button = gtk_toggle_button_new();
2042 GtkRcStyle *rcstyle;
2043 GValue *prop;
2044 gint i;
2045 struct image_pair *images;
2047 images = g_new(struct image_pair, 1);
2048 /* Since these may not be added at any point, make sure to
2049 * sink them. */
2050 images->on = on_widget;
2051 g_object_ref(G_OBJECT(images->on));
2052 gtk_object_sink(GTK_OBJECT(images->on));
2053 gtk_widget_show(images->on);
2055 images->off = off_widget;
2056 g_object_ref(G_OBJECT(images->off));
2057 gtk_object_sink(GTK_OBJECT(images->off));
2058 gtk_widget_show(images->off);
2060 /* Make border as small as possible */
2061 gtk_misc_set_padding(GTK_MISC(images->on), 0, 0);
2062 gtk_misc_set_padding(GTK_MISC(images->off), 0, 0);
2063 GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(button), GTK_CAN_FOCUS);
2064 GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(button), GTK_CAN_DEFAULT);
2066 rcstyle = gtk_rc_style_new ();
2067 rcstyle->xthickness = rcstyle->ythickness = 0;
2068 gtk_widget_modify_style (button, rcstyle);
2069 gtk_rc_style_unref (rcstyle);
2071 prop = g_new0(GValue, 1);
2072 g_value_init(prop, G_TYPE_INT);
2073 gtk_widget_style_get_property(GTK_WIDGET(button), "focus-padding", prop);
2074 i = g_value_get_int(prop);
2075 g_value_set_int(prop, 0);
2077 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
2078 /* gtk_button_set_focus_on_click(GTK_BUTTON(button), FALSE);*/
2079 gtk_container_set_border_width(GTK_CONTAINER(button), 0);
2081 gtk_container_add(GTK_CONTAINER(button), images->off);
2083 g_signal_connect(G_OBJECT(button), "toggled",
2084 G_CALLBACK(dia_toggle_button_swap_images), images);
2085 g_signal_connect(G_OBJECT(button), "destroy",
2086 G_CALLBACK(dia_toggle_button_destroy), images);
2088 return button;
2091 /** Create a toggle button with two icons (created with gdk-pixbuf-csource,
2092 * for instance). The icons represent on and off.
2094 GtkWidget *
2095 dia_toggle_button_new_with_icons(const guint8 *on_icon,
2096 const guint8 *off_icon)
2098 GdkPixbuf *p1, *p2;
2100 p1 = gdk_pixbuf_new_from_inline(-1, on_icon, FALSE, NULL);
2101 p2 = gdk_pixbuf_new_from_inline(-1, off_icon, FALSE, NULL);
2103 return dia_toggle_button_new(gtk_image_new_from_pixbuf(p1),
2104 gtk_image_new_from_pixbuf(p2));