1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * Massively updated for Pango by Owen Taylor, May 2000
5 * GtkFontSelection widget for Gtk+, by Damon Chaplin, May 1998.
6 * Based on the GnomeFontSelector widget, by Elliot Lee, but major changes.
7 * The GnomeFontSelector was derived from app/text_tool.c in the GIMP.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
26 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
27 * file for a list of people on the GTK+ Team. See the ChangeLog
28 * files for a list of changes. These files are distributed with
29 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
37 #include "gdk/gdkkeysyms.h"
39 #include "gtkfontsel.h"
41 #include "gtkbutton.h"
42 #include "gtkcellrenderertext.h"
48 #include "gtkliststore.h"
50 #include "gtksignal.h"
53 #include "gtktreeselection.h"
54 #include "gtktreeview.h"
56 #include "gtkscrolledwindow.h"
59 /* We don't enable the font and style entries because they don't add
60 * much in terms of visible effect and have a weird effect on keynav.
61 * the Windows font selector has entries similarly positioned but they
62 * act in conjunction with the associated lists to form a single focus
65 #undef INCLUDE_FONT_ENTRIES
67 /* This is the default text shown in the preview entry, though the user
68 can set it. Remember that some fonts only have capital letters. */
69 #define PREVIEW_TEXT N_("abcdefghijk ABCDEFGHIJK")
71 /* This is the initial and maximum height of the preview entry (it expands
72 when large font sizes are selected). Initial height is also the minimum. */
73 #define INITIAL_PREVIEW_HEIGHT 44
74 #define MAX_PREVIEW_HEIGHT 300
76 /* These are the sizes of the font, style & size lists. */
77 #define FONT_LIST_HEIGHT 136
78 #define FONT_LIST_WIDTH 190
79 #define FONT_STYLE_LIST_WIDTH 170
80 #define FONT_SIZE_LIST_WIDTH 60
82 /* These are what we use as the standard font sizes, for the size list.
84 static const guint16 font_sizes[] = {
85 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
86 32, 36, 40, 48, 56, 64, 72
111 static void gtk_font_selection_class_init (GtkFontSelectionClass *klass);
112 static void gtk_font_selection_set_property (GObject *object,
116 static void gtk_font_selection_get_property (GObject *object,
120 static void gtk_font_selection_init (GtkFontSelection *fontsel);
121 static void gtk_font_selection_finalize (GObject *object);
123 /* These are the callbacks & related functions. */
124 static void gtk_font_selection_select_font (GtkTreeSelection *selection,
126 static void gtk_font_selection_show_available_fonts (GtkFontSelection *fs);
128 static void gtk_font_selection_show_available_styles (GtkFontSelection *fs);
129 static void gtk_font_selection_select_best_style (GtkFontSelection *fs,
131 static void gtk_font_selection_select_style (GtkTreeSelection *selection,
134 static void gtk_font_selection_select_best_size (GtkFontSelection *fs);
135 static void gtk_font_selection_show_available_sizes (GtkFontSelection *fs,
136 gboolean first_time);
137 static void gtk_font_selection_size_activate (GtkWidget *w,
139 static void gtk_font_selection_select_size (GtkTreeSelection *selection,
142 static void gtk_font_selection_scroll_on_map (GtkWidget *w,
145 static void gtk_font_selection_preview_changed (GtkWidget *entry,
146 GtkFontSelection *fontsel);
148 /* Misc. utility functions. */
149 static void gtk_font_selection_load_font (GtkFontSelection *fs);
150 static void gtk_font_selection_update_preview (GtkFontSelection *fs);
152 /* FontSelectionDialog */
153 static void gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass);
154 static void gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag);
156 static gint gtk_font_selection_dialog_on_configure (GtkWidget *widget,
157 GdkEventConfigure *event,
158 GtkFontSelectionDialog *fsd);
160 static GtkWindowClass *font_selection_parent_class = NULL;
161 static GtkVBoxClass *font_selection_dialog_parent_class = NULL;
164 gtk_font_selection_get_type ()
166 static GtkType font_selection_type = 0;
168 if (!font_selection_type)
170 static const GtkTypeInfo fontsel_type_info =
173 sizeof (GtkFontSelection),
174 sizeof (GtkFontSelectionClass),
175 (GtkClassInitFunc) gtk_font_selection_class_init,
176 (GtkObjectInitFunc) gtk_font_selection_init,
177 /* reserved_1 */ NULL,
178 /* reserved_2 */ NULL,
179 (GtkClassInitFunc) NULL,
182 font_selection_type = gtk_type_unique (GTK_TYPE_VBOX,
186 return font_selection_type;
190 gtk_font_selection_class_init (GtkFontSelectionClass *klass)
192 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
194 font_selection_parent_class = gtk_type_class (GTK_TYPE_VBOX);
196 gobject_class->set_property = gtk_font_selection_set_property;
197 gobject_class->get_property = gtk_font_selection_get_property;
199 g_object_class_install_property (gobject_class,
201 g_param_spec_string ("font_name",
203 _("The X string that represents this font."),
206 g_object_class_install_property (gobject_class,
208 g_param_spec_boxed ("font",
210 _("The GdkFont that is currently selected."),
213 g_object_class_install_property (gobject_class,
215 g_param_spec_string ("preview_text",
217 _("The text to display in order to demonstrate the selected font."),
220 gobject_class->finalize = gtk_font_selection_finalize;
224 gtk_font_selection_set_property (GObject *object,
229 GtkFontSelection *fontsel;
231 fontsel = GTK_FONT_SELECTION (object);
236 gtk_font_selection_set_font_name (fontsel, g_value_get_string (value));
238 case PROP_PREVIEW_TEXT:
239 gtk_font_selection_set_preview_text (fontsel, g_value_get_string (value));
242 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
247 static void gtk_font_selection_get_property (GObject *object,
252 GtkFontSelection *fontsel;
254 fontsel = GTK_FONT_SELECTION (object);
259 g_value_set_string (value, gtk_font_selection_get_font_name (fontsel));
262 g_value_set_object (value, gtk_font_selection_get_font (fontsel));
264 case PROP_PREVIEW_TEXT:
265 g_value_set_string (value, gtk_font_selection_get_preview_text (fontsel));
268 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
275 gtk_font_selection_init (GtkFontSelection *fontsel)
277 GtkWidget *scrolled_win;
278 GtkWidget *text_frame;
280 GtkWidget *table, *label;
281 GtkWidget *font_label, *style_label;
283 GtkTreeViewColumn *column;
284 GList *focus_chain = NULL;
286 gtk_widget_push_composite_child ();
288 fontsel->size = 12 * PANGO_SCALE;
290 /* Create the table of font, style & size. */
291 table = gtk_table_new (3, 3, FALSE);
292 gtk_widget_show (table);
293 gtk_table_set_col_spacings (GTK_TABLE (table), 8);
294 gtk_box_pack_start (GTK_BOX (fontsel), table, TRUE, TRUE, 0);
296 #ifdef INCLUDE_FONT_ENTRIES
297 fontsel->font_entry = gtk_entry_new ();
298 gtk_entry_set_editable (GTK_ENTRY (fontsel->font_entry), FALSE);
299 gtk_widget_set_usize (fontsel->font_entry, 20, -1);
300 gtk_widget_show (fontsel->font_entry);
301 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
304 fontsel->font_style_entry = gtk_entry_new ();
305 gtk_entry_set_editable (GTK_ENTRY (fontsel->font_style_entry), FALSE);
306 gtk_widget_set_usize (fontsel->font_style_entry, 20, -1);
307 gtk_widget_show (fontsel->font_style_entry);
308 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
310 #endif /* INCLUDE_FONT_ENTRIES */
312 fontsel->size_entry = gtk_entry_new ();
313 gtk_widget_set_usize (fontsel->size_entry, 20, -1);
314 gtk_widget_show (fontsel->size_entry);
315 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
317 gtk_signal_connect (GTK_OBJECT (fontsel->size_entry), "activate",
318 (GtkSignalFunc) gtk_font_selection_size_activate,
321 font_label = gtk_label_new_with_mnemonic (_("_Family:"));
322 gtk_misc_set_alignment (GTK_MISC (font_label), 0.0, 0.5);
323 gtk_widget_show (font_label);
324 gtk_table_attach (GTK_TABLE (table), font_label, 0, 1, 0, 1,
327 style_label = gtk_label_new_with_mnemonic (_("_Style:"));
328 gtk_misc_set_alignment (GTK_MISC (style_label), 0.0, 0.5);
329 gtk_widget_show (style_label);
330 gtk_table_attach (GTK_TABLE (table), style_label, 1, 2, 0, 1,
333 label = gtk_label_new_with_mnemonic (_("Si_ze:"));
334 gtk_label_set_mnemonic_widget (GTK_LABEL (label),
335 fontsel->size_entry);
336 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
337 gtk_widget_show (label);
338 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
342 /* Create the lists */
344 model = gtk_list_store_new (2,
345 G_TYPE_OBJECT, /* FAMILY_COLUMN */
346 G_TYPE_STRING); /* FAMILY_NAME_COLUMN */
347 fontsel->family_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
348 g_object_unref (model);
350 column = gtk_tree_view_column_new_with_attributes ("Family",
351 gtk_cell_renderer_text_new (),
352 "text", FAMILY_NAME_COLUMN,
354 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
355 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->family_list), column);
357 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->family_list), FALSE);
358 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)),
359 GTK_SELECTION_BROWSE);
361 gtk_label_set_mnemonic_widget (GTK_LABEL (font_label), fontsel->family_list);
363 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
364 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
365 gtk_widget_set_usize (scrolled_win, FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
366 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->family_list);
367 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
368 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
369 gtk_widget_show (fontsel->family_list);
370 gtk_widget_show (scrolled_win);
372 gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 1, 3,
373 GTK_EXPAND | GTK_FILL,
374 GTK_EXPAND | GTK_FILL, 0, 0);
375 focus_chain = g_list_append (focus_chain, scrolled_win);
377 model = gtk_list_store_new (2,
378 G_TYPE_OBJECT, /* FACE_COLUMN */
379 G_TYPE_STRING); /* FACE_NAME_COLUMN */
380 fontsel->face_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
381 g_object_unref (model);
383 gtk_label_set_mnemonic_widget (GTK_LABEL (style_label), fontsel->face_list);
385 column = gtk_tree_view_column_new_with_attributes ("Face",
386 gtk_cell_renderer_text_new (),
387 "text", FACE_NAME_COLUMN,
389 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
390 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->face_list), column);
392 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->face_list), FALSE);
393 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)),
394 GTK_SELECTION_BROWSE);
396 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
397 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
398 gtk_widget_set_usize (scrolled_win, FONT_STYLE_LIST_WIDTH, FONT_LIST_HEIGHT);
399 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->face_list);
400 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
401 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
402 gtk_widget_show (fontsel->face_list);
403 gtk_widget_show (scrolled_win);
404 gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 1, 3,
405 GTK_EXPAND | GTK_FILL,
406 GTK_EXPAND | GTK_FILL, 0, 0);
407 focus_chain = g_list_append (focus_chain, scrolled_win);
409 focus_chain = g_list_append (focus_chain, fontsel->size_entry);
411 model = gtk_list_store_new (1, G_TYPE_INT);
412 fontsel->size_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
413 g_object_unref (model);
415 column = gtk_tree_view_column_new_with_attributes ("Size",
416 gtk_cell_renderer_text_new (),
419 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
420 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->size_list), column);
422 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->size_list), FALSE);
423 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)),
424 GTK_SELECTION_BROWSE);
426 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
427 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
428 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_list);
429 gtk_widget_set_usize (scrolled_win, -1, FONT_LIST_HEIGHT);
430 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
431 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
432 gtk_widget_show (fontsel->size_list);
433 gtk_widget_show (scrolled_win);
434 gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
435 GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
436 focus_chain = g_list_append (focus_chain, scrolled_win);
438 gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
439 g_list_free (focus_chain);
441 /* Insert the fonts. */
442 gtk_font_selection_show_available_fonts (fontsel);
444 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)), "changed",
445 G_CALLBACK (gtk_font_selection_select_font), fontsel);
447 gtk_signal_connect_after (GTK_OBJECT (fontsel->family_list), "map",
448 GTK_SIGNAL_FUNC (gtk_font_selection_scroll_on_map),
451 gtk_font_selection_show_available_styles (fontsel);
453 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)), "changed",
454 G_CALLBACK (gtk_font_selection_select_style), fontsel);
456 gtk_font_selection_show_available_sizes (fontsel, TRUE);
458 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)), "changed",
459 G_CALLBACK (gtk_font_selection_select_size), fontsel);
461 /* create the text entry widget */
462 label = gtk_label_new_with_mnemonic (_("_Preview:"));
463 gtk_widget_show (label);
465 text_frame = gtk_frame_new (NULL);
466 gtk_frame_set_label_widget (GTK_FRAME (text_frame), label);
468 gtk_widget_show (text_frame);
469 gtk_frame_set_shadow_type (GTK_FRAME (text_frame), GTK_SHADOW_ETCHED_IN);
470 gtk_box_pack_start (GTK_BOX (fontsel), text_frame,
473 /* This is just used to get a 4-pixel space around the preview entry. */
474 text_box = gtk_hbox_new (FALSE, 0);
475 gtk_widget_show (text_box);
476 gtk_container_add (GTK_CONTAINER (text_frame), text_box);
477 gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
479 fontsel->preview_entry = gtk_entry_new ();
480 gtk_label_set_mnemonic_widget (GTK_LABEL (label), fontsel->preview_entry);
482 gtk_widget_show (fontsel->preview_entry);
483 gtk_signal_connect (GTK_OBJECT (fontsel->preview_entry), "changed",
484 (GtkSignalFunc) gtk_font_selection_preview_changed,
486 gtk_widget_set_usize (fontsel->preview_entry, -1, INITIAL_PREVIEW_HEIGHT);
487 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
490 gtk_font_selection_update_preview (fontsel);
492 gtk_widget_pop_composite_child();
496 gtk_font_selection_new ()
498 GtkFontSelection *fontsel;
500 fontsel = gtk_type_new (GTK_TYPE_FONT_SELECTION);
502 return GTK_WIDGET (fontsel);
506 gtk_font_selection_finalize (GObject *object)
508 GtkFontSelection *fontsel;
510 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
512 fontsel = GTK_FONT_SELECTION (object);
515 gdk_font_unref (fontsel->font);
517 if (G_OBJECT_CLASS (font_selection_parent_class)->finalize)
518 (* G_OBJECT_CLASS (font_selection_parent_class)->finalize) (object);
522 gtk_font_selection_preview_changed (GtkWidget *entry,
523 GtkFontSelection *fontsel)
525 g_object_notify (G_OBJECT (fontsel), "preview_text");
529 scroll_to_selection (GtkTreeView *tree_view)
531 GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
535 if (gtk_tree_selection_get_selected (selection, &model, &iter))
537 GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
538 gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5);
539 gtk_tree_path_free (path);
544 set_cursor_to_iter (GtkTreeView *view,
547 GtkTreeModel *model = gtk_tree_view_get_model (view);
548 GtkTreePath *path = gtk_tree_model_get_path (model, iter);
550 gtk_tree_view_set_cursor (view, path, 0, FALSE);
552 gtk_tree_path_free (path);
555 /* This is called when the list is mapped. Here we scroll to the current
556 font if necessary. */
558 gtk_font_selection_scroll_on_map (GtkWidget *widget,
561 GtkFontSelection *fontsel;
564 g_message ("In expose_list\n");
566 fontsel = GTK_FONT_SELECTION (data);
568 /* Try to scroll the font family list to the selected item */
569 scroll_to_selection (GTK_TREE_VIEW (fontsel->family_list));
571 /* Try to scroll the font family list to the selected item */
572 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
574 /* Try to scroll the font family list to the selected item */
575 scroll_to_selection (GTK_TREE_VIEW (fontsel->size_list));
578 /* This is called when a family is selected in the list. */
580 gtk_font_selection_select_font (GtkTreeSelection *selection,
583 GtkFontSelection *fontsel;
586 const gchar *family_name;
588 fontsel = GTK_FONT_SELECTION (data);
590 if (gtk_tree_selection_get_selected (selection, &model, &iter))
592 PangoFontFamily *family;
594 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
595 if (fontsel->family != family)
597 fontsel->family = family;
599 family_name = pango_font_family_get_name (fontsel->family);
601 #ifdef INCLUDE_FONT_ENTRIES
602 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
605 gtk_font_selection_show_available_styles (fontsel);
606 gtk_font_selection_select_best_style (fontsel, TRUE);
609 g_object_unref (family);
614 cmp_families (const void *a, const void *b)
616 const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
617 const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
619 return strcmp (a_name, b_name);
623 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
626 PangoFontFamily **families;
627 PangoFontFamily *match_family = NULL;
629 GtkTreeIter match_row;
631 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list)));
633 pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
634 &families, &n_families);
635 qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families);
637 gtk_list_store_clear (model);
639 for (i=0; i<n_families; i++)
641 const gchar *name = pango_font_family_get_name (families[i]);
644 gtk_list_store_append (model, &iter);
645 gtk_list_store_set (model, &iter,
646 FAMILY_COLUMN, families[i],
647 FAMILY_NAME_COLUMN, name,
650 if (i == 0 || !g_ascii_strcasecmp (name, "sans"))
652 match_family = families[i];
657 fontsel->family = match_family;
660 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &match_row);
661 #ifdef INCLUDE_FONT_ENTRIES
662 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry),
663 pango_font_family_get_name (match_family));
664 #endif /* INCLUDE_FONT_ENTRIES */
671 compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
673 int val = strcmp (pango_font_description_get_family (a), pango_font_description_get_family (b));
677 if (pango_font_description_get_weight (a) != pango_font_description_get_weight (b))
678 return pango_font_description_get_weight (a) - pango_font_description_get_weight (b);
680 if (pango_font_description_get_style (a) != pango_font_description_get_style (b))
681 return pango_font_description_get_style (a) - pango_font_description_get_style (b);
683 if (pango_font_description_get_stretch (a) != pango_font_description_get_stretch (b))
684 return pango_font_description_get_stretch (a) - pango_font_description_get_stretch (b);
686 if (pango_font_description_get_variant (a) != pango_font_description_get_variant (b))
687 return pango_font_description_get_variant (a) - pango_font_description_get_variant (b);
693 faces_sort_func (const void *a, const void *b)
695 PangoFontDescription *desc_a = pango_font_face_describe (*(PangoFontFace **)a);
696 PangoFontDescription *desc_b = pango_font_face_describe (*(PangoFontFace **)b);
698 int ord = compare_font_descriptions (desc_a, desc_b);
700 pango_font_description_free (desc_a);
701 pango_font_description_free (desc_b);
707 font_description_style_equal (const PangoFontDescription *a,
708 const PangoFontDescription *b)
710 return (pango_font_description_get_weight (a) == pango_font_description_get_weight (b) &&
711 pango_font_description_get_style (a) == pango_font_description_get_style (b) &&
712 pango_font_description_get_stretch (a) == pango_font_description_get_stretch (b) &&
713 pango_font_description_get_variant (a) == pango_font_description_get_variant (b));
716 /* This fills the font style list with all the possible style combinations
717 for the current font family. */
719 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
722 PangoFontFace **faces;
723 PangoFontDescription *old_desc;
725 GtkTreeIter match_row;
726 PangoFontFace *match_face = NULL;
728 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list)));
731 old_desc = pango_font_face_describe (fontsel->face);
735 pango_font_family_list_faces (fontsel->family, &faces, &n_faces);
736 qsort (faces, n_faces, sizeof (PangoFontFace *), faces_sort_func);
738 gtk_list_store_clear (model);
740 for (i=0; i < n_faces; i++)
743 const gchar *str = pango_font_face_get_face_name (faces[i]);
745 gtk_list_store_append (model, &iter);
746 gtk_list_store_set (model, &iter,
747 FACE_COLUMN, faces[i],
748 FACE_NAME_COLUMN, str,
754 match_face = faces[i];
758 PangoFontDescription *tmp_desc = pango_font_face_describe (faces[i]);
760 if (font_description_style_equal (tmp_desc, old_desc))
763 match_face = faces[i];
766 pango_font_description_free (tmp_desc);
771 pango_font_description_free (old_desc);
773 fontsel->face = match_face;
776 const gchar *str = pango_font_face_get_face_name (fontsel->face);
778 #ifdef INCLUDE_FONT_ENTRIES
779 gtk_entry_set_text (GTK_ENTRY (fontsel->font_style_entry), str);
781 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_row);
787 /* This selects a style when the user selects a font. It just uses the first
788 available style at present. I was thinking of trying to maintain the
789 selected style, e.g. bold italic, when the user selects different fonts.
790 However, the interface is so easy to use now I'm not sure it's worth it.
791 Note: This will load a font. */
793 gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
799 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
801 if (gtk_tree_model_get_iter_first (model, &iter))
803 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &iter);
804 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
807 gtk_font_selection_show_available_sizes (fontsel, FALSE);
808 gtk_font_selection_select_best_size (fontsel);
812 /* This is called when a style is selected in the list. */
814 gtk_font_selection_select_style (GtkTreeSelection *selection,
817 GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
821 if (gtk_tree_selection_get_selected (selection, &model, &iter))
825 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
826 fontsel->face = face;
828 g_object_unref (face);
831 gtk_font_selection_show_available_sizes (fontsel, FALSE);
832 gtk_font_selection_select_best_size (fontsel);
836 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel,
841 GtkTreeSelection *selection;
845 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
846 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
848 /* Insert the standard font sizes */
851 gtk_list_store_clear (model);
853 for (i = 0; i < G_N_ELEMENTS (font_sizes); i++)
857 gtk_list_store_append (model, &iter);
858 gtk_list_store_set (model, &iter, SIZE_COLUMN, font_sizes[i], -1);
860 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
861 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
867 gboolean found = FALSE;
869 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
870 for (i = 0; i < G_N_ELEMENTS (font_sizes) && !found; i++)
872 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
874 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
878 gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
883 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
884 gtk_tree_selection_unselect_all (selection);
888 /* Set the entry to the new size, rounding to 1 digit,
889 * trimming of trailing 0's and a trailing period
891 sprintf (buffer, "%.1f", fontsel->size / (1.0 * PANGO_SCALE));
892 if (strchr (buffer, '.'))
894 p = buffer + strlen (buffer) - 1;
902 /* Compare, to avoid moving the cursor unecessarily */
903 if (strcmp (gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry)), buffer) != 0)
904 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
908 gtk_font_selection_select_best_size (GtkFontSelection *fontsel)
910 gtk_font_selection_load_font (fontsel);
914 gtk_font_selection_set_size (GtkFontSelection *fontsel,
917 if (fontsel->size != new_size)
919 fontsel->size = new_size;
921 gtk_font_selection_show_available_sizes (fontsel, FALSE);
922 gtk_font_selection_load_font (fontsel);
926 /* If the user hits return in the font size entry, we change to the new font
929 gtk_font_selection_size_activate (GtkWidget *w,
932 GtkFontSelection *fontsel;
936 fontsel = GTK_FONT_SELECTION (data);
938 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
939 new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
941 gtk_font_selection_set_size (fontsel, new_size);
944 /* This is called when a size is selected in the list. */
946 gtk_font_selection_select_size (GtkTreeSelection *selection,
949 GtkFontSelection *fontsel;
954 fontsel = GTK_FONT_SELECTION (data);
956 if (gtk_tree_selection_get_selected (selection, &model, &iter))
958 gtk_tree_model_get (model, &iter, SIZE_COLUMN, &new_size, -1);
959 gtk_font_selection_set_size (fontsel, new_size * PANGO_SCALE);
964 gtk_font_selection_load_font (GtkFontSelection *fontsel)
967 gdk_font_unref (fontsel->font);
968 fontsel->font = NULL;
970 gtk_font_selection_update_preview (fontsel);
973 static PangoFontDescription *
974 gtk_font_selection_get_font_description (GtkFontSelection *fontsel)
976 PangoFontDescription *font_desc = pango_font_face_describe (fontsel->face);
977 pango_font_description_set_size (font_desc, fontsel->size);
982 /* This sets the font in the preview entry to the selected font, and tries to
983 make sure that the preview entry is a reasonable size, i.e. so that the
984 text can be seen with a bit of space to spare. But it tries to avoid
985 resizing the entry every time the font changes.
986 This also used to shrink the preview if the font size was decreased, but
987 that made it awkward if the user wanted to resize the window themself. */
989 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
991 GtkRcStyle *rc_style;
993 GtkRequisition old_requisition;
994 GtkWidget *preview_entry = fontsel->preview_entry;
997 gtk_widget_get_child_requisition (preview_entry, &old_requisition);
999 rc_style = gtk_rc_style_new ();
1000 rc_style->font_desc = gtk_font_selection_get_font_description (fontsel);
1002 gtk_widget_modify_style (preview_entry, rc_style);
1003 gtk_rc_style_unref (rc_style);
1005 gtk_widget_size_request (preview_entry, NULL);
1007 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1008 new_height = CLAMP (preview_entry->requisition.height, INITIAL_PREVIEW_HEIGHT, MAX_PREVIEW_HEIGHT);
1010 if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
1011 gtk_widget_set_usize (preview_entry, -1, new_height);
1013 /* This sets the preview text, if it hasn't been set already. */
1014 text = gtk_entry_get_text (GTK_ENTRY (preview_entry));
1015 if (strlen (text) == 0)
1016 gtk_entry_set_text (GTK_ENTRY (preview_entry), _(PREVIEW_TEXT));
1017 gtk_entry_set_position (GTK_ENTRY (preview_entry), 0);
1020 /*****************************************************************************
1021 * These functions are the main public interface for getting/setting the font.
1022 *****************************************************************************/
1025 gtk_font_selection_get_font (GtkFontSelection *fontsel)
1029 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1030 fontsel->font = gdk_font_from_description (font_desc);
1031 pango_font_description_free (font_desc);
1034 return fontsel->font;
1039 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
1043 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1044 result = pango_font_description_to_string (font_desc);
1045 pango_font_description_free (font_desc);
1051 /* This sets the current font, selecting the appropriate list rows.
1052 First we check the fontname is valid and try to find the font family
1053 - i.e. the name in the main list. If we can't find that, then just return.
1054 Next we try to set each of the properties according to the fontname.
1055 Finally we select the font family & style in the lists. */
1057 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
1058 const gchar *fontname)
1060 PangoFontFamily *new_family = NULL;
1061 PangoFontFace *new_face = NULL;
1062 PangoFontFace *fallback_face = NULL;
1063 PangoFontDescription *new_desc;
1064 GtkTreeModel *model;
1066 GtkTreeIter match_iter;
1069 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
1071 new_desc = pango_font_description_from_string (fontname);
1073 /* Check to make sure that this is in the list of allowed fonts */
1075 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list));
1076 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1078 valid = gtk_tree_model_iter_next (model, &iter))
1080 PangoFontFamily *family;
1082 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
1084 if (g_ascii_strcasecmp (pango_font_family_get_name (family),
1085 pango_font_description_get_family (new_desc)) == 0)
1086 new_family = family;
1088 g_object_unref (family);
1097 fontsel->family = new_family;
1098 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &iter);
1099 gtk_font_selection_show_available_styles (fontsel);
1101 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1102 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1104 valid = gtk_tree_model_iter_next (model, &iter))
1106 PangoFontFace *face;
1107 PangoFontDescription *tmp_desc;
1109 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
1110 tmp_desc = pango_font_face_describe (face);
1112 if (font_description_style_equal (tmp_desc, new_desc))
1117 fallback_face = face;
1121 pango_font_description_free (tmp_desc);
1122 g_object_unref (face);
1132 new_face = fallback_face;
1134 fontsel->face = new_face;
1135 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_iter);
1137 gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
1139 g_object_freeze_notify (G_OBJECT (fontsel));
1140 g_object_notify (G_OBJECT (fontsel), "font_name");
1141 g_object_notify (G_OBJECT (fontsel), "font");
1142 g_object_thaw_notify (G_OBJECT (fontsel));
1144 pango_font_description_free (new_desc);
1150 /* This returns the text in the preview entry. You should copy the returned
1151 text if you need it. */
1152 G_CONST_RETURN gchar*
1153 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
1155 return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
1159 /* This sets the text in the preview entry. */
1161 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
1164 gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
1167 /*****************************************************************************
1168 * GtkFontSelectionDialog
1169 *****************************************************************************/
1172 gtk_font_selection_dialog_get_type (void)
1174 static GtkType font_selection_dialog_type = 0;
1176 if (!font_selection_dialog_type)
1178 GtkTypeInfo fontsel_diag_info =
1180 "GtkFontSelectionDialog",
1181 sizeof (GtkFontSelectionDialog),
1182 sizeof (GtkFontSelectionDialogClass),
1183 (GtkClassInitFunc) gtk_font_selection_dialog_class_init,
1184 (GtkObjectInitFunc) gtk_font_selection_dialog_init,
1185 /* reserved_1 */ NULL,
1186 /* reserved_2 */ NULL,
1187 (GtkClassInitFunc) NULL,
1190 font_selection_dialog_type = gtk_type_unique (GTK_TYPE_DIALOG,
1191 &fontsel_diag_info);
1194 return font_selection_dialog_type;
1198 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1200 GtkObjectClass *object_class;
1202 object_class = (GtkObjectClass*) klass;
1204 font_selection_dialog_parent_class = gtk_type_class (GTK_TYPE_DIALOG);
1208 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1212 gtk_widget_push_composite_child ();
1214 dialog = GTK_DIALOG (fontseldiag);
1216 fontseldiag->dialog_width = -1;
1217 fontseldiag->auto_resize = TRUE;
1219 gtk_widget_set_events (GTK_WIDGET (fontseldiag), GDK_STRUCTURE_MASK);
1220 gtk_signal_connect (GTK_OBJECT (fontseldiag), "configure_event",
1221 (GtkSignalFunc) gtk_font_selection_dialog_on_configure,
1224 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
1225 gtk_window_set_policy (GTK_WINDOW (fontseldiag), FALSE, TRUE, TRUE);
1227 fontseldiag->main_vbox = dialog->vbox;
1229 fontseldiag->fontsel = gtk_font_selection_new ();
1230 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 4);
1231 gtk_widget_show (fontseldiag->fontsel);
1232 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
1233 fontseldiag->fontsel, TRUE, TRUE, 0);
1235 /* Create the action area */
1236 fontseldiag->action_area = dialog->action_area;
1238 fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1240 GTK_RESPONSE_CANCEL);
1242 fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1244 GTK_RESPONSE_APPLY);
1245 gtk_widget_hide (fontseldiag->apply_button);
1247 fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1250 gtk_widget_grab_default (fontseldiag->ok_button);
1252 gtk_window_set_title (GTK_WINDOW (fontseldiag),
1253 _("Font Selection"));
1255 gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
1257 gtk_widget_pop_composite_child ();
1261 gtk_font_selection_dialog_new (const gchar *title)
1263 GtkFontSelectionDialog *fontseldiag;
1265 fontseldiag = gtk_type_new (GTK_TYPE_FONT_SELECTION_DIALOG);
1268 gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1270 return GTK_WIDGET (fontseldiag);
1274 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1276 return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1280 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1282 return gtk_font_selection_get_font (GTK_FONT_SELECTION (fsd->fontsel));
1286 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1287 const gchar *fontname)
1289 return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1292 G_CONST_RETURN gchar*
1293 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1295 return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1299 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1302 gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);
1306 /* This turns auto-shrink off if the user resizes the width of the dialog.
1307 It also turns it back on again if the user resizes it back to its normal
1310 gtk_font_selection_dialog_on_configure (GtkWidget *widget,
1311 GdkEventConfigure *event,
1312 GtkFontSelectionDialog *fsd)
1314 /* This sets the initial width. */
1315 if (fsd->dialog_width == -1)
1316 fsd->dialog_width = event->width;
1317 else if (fsd->auto_resize && fsd->dialog_width != event->width)
1319 fsd->auto_resize = FALSE;
1320 gtk_window_set_policy (GTK_WINDOW (fsd), FALSE, TRUE, FALSE);
1322 else if (!fsd->auto_resize && fsd->dialog_width == event->width)
1324 fsd->auto_resize = TRUE;
1325 gtk_window_set_policy (GTK_WINDOW (fsd), FALSE, TRUE, TRUE);