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 /* This is the default text shown in the preview entry, though the user
60 can set it. Remember that some fonts only have capital letters. */
61 #define PREVIEW_TEXT "abcdefghijk ABCDEFGHIJK"
63 /* This is the initial and maximum height of the preview entry (it expands
64 when large font sizes are selected). Initial height is also the minimum. */
65 #define INITIAL_PREVIEW_HEIGHT 44
66 #define MAX_PREVIEW_HEIGHT 300
68 /* These are the sizes of the font, style & size lists. */
69 #define FONT_LIST_HEIGHT 136
70 #define FONT_LIST_WIDTH 190
71 #define FONT_STYLE_LIST_WIDTH 170
72 #define FONT_SIZE_LIST_WIDTH 60
74 /* These are what we use as the standard font sizes, for the size list.
76 static const guint16 font_sizes[] = {
77 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
78 32, 36, 40, 48, 56, 64, 72
103 static void gtk_font_selection_class_init (GtkFontSelectionClass *klass);
104 static void gtk_font_selection_set_property (GObject *object,
108 static void gtk_font_selection_get_property (GObject *object,
112 static void gtk_font_selection_init (GtkFontSelection *fontsel);
113 static void gtk_font_selection_finalize (GObject *object);
115 /* These are the callbacks & related functions. */
116 static void gtk_font_selection_select_font (GtkTreeSelection *selection,
118 static void gtk_font_selection_show_available_fonts (GtkFontSelection *fs);
120 static void gtk_font_selection_show_available_styles (GtkFontSelection *fs);
121 static void gtk_font_selection_select_best_style (GtkFontSelection *fs,
123 static void gtk_font_selection_select_style (GtkTreeSelection *selection,
126 static void gtk_font_selection_select_best_size (GtkFontSelection *fs);
127 static void gtk_font_selection_show_available_sizes (GtkFontSelection *fs,
128 gboolean first_time);
129 static void gtk_font_selection_size_activate (GtkWidget *w,
131 static void gtk_font_selection_select_size (GtkTreeSelection *selection,
134 static void gtk_font_selection_scroll_on_map (GtkWidget *w,
137 static void gtk_font_selection_preview_changed (GtkWidget *entry,
138 GtkFontSelection *fontsel);
140 /* Misc. utility functions. */
141 static void gtk_font_selection_load_font (GtkFontSelection *fs);
142 static void gtk_font_selection_update_preview (GtkFontSelection *fs);
144 /* FontSelectionDialog */
145 static void gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass);
146 static void gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag);
148 static gint gtk_font_selection_dialog_on_configure (GtkWidget *widget,
149 GdkEventConfigure *event,
150 GtkFontSelectionDialog *fsd);
152 static GtkWindowClass *font_selection_parent_class = NULL;
153 static GtkVBoxClass *font_selection_dialog_parent_class = NULL;
156 gtk_font_selection_get_type ()
158 static GtkType font_selection_type = 0;
160 if (!font_selection_type)
162 static const GtkTypeInfo fontsel_type_info =
165 sizeof (GtkFontSelection),
166 sizeof (GtkFontSelectionClass),
167 (GtkClassInitFunc) gtk_font_selection_class_init,
168 (GtkObjectInitFunc) gtk_font_selection_init,
169 /* reserved_1 */ NULL,
170 /* reserved_2 */ NULL,
171 (GtkClassInitFunc) NULL,
174 font_selection_type = gtk_type_unique (GTK_TYPE_VBOX,
178 return font_selection_type;
182 gtk_font_selection_class_init (GtkFontSelectionClass *klass)
184 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
186 font_selection_parent_class = gtk_type_class (GTK_TYPE_VBOX);
188 gobject_class->set_property = gtk_font_selection_set_property;
189 gobject_class->get_property = gtk_font_selection_get_property;
191 g_object_class_install_property (gobject_class,
193 g_param_spec_string ("font_name",
195 _("The X string that represents this font."),
198 g_object_class_install_property (gobject_class,
200 g_param_spec_boxed ("font",
202 _("The GdkFont that is currently selected."),
205 g_object_class_install_property (gobject_class,
207 g_param_spec_string ("preview_text",
209 _("The text to display in order to demonstrate the selected font."),
212 gobject_class->finalize = gtk_font_selection_finalize;
216 gtk_font_selection_set_property (GObject *object,
221 GtkFontSelection *fontsel;
223 fontsel = GTK_FONT_SELECTION (object);
228 gtk_font_selection_set_font_name (fontsel, g_value_get_string (value));
230 case PROP_PREVIEW_TEXT:
231 gtk_font_selection_set_preview_text (fontsel, g_value_get_string (value));
234 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
239 static void gtk_font_selection_get_property (GObject *object,
244 GtkFontSelection *fontsel;
246 fontsel = GTK_FONT_SELECTION (object);
251 g_value_set_string (value, gtk_font_selection_get_font_name (fontsel));
254 g_value_set_object (value, gtk_font_selection_get_font (fontsel));
256 case PROP_PREVIEW_TEXT:
257 g_value_set_string (value, gtk_font_selection_get_preview_text (fontsel));
260 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
267 gtk_font_selection_init (GtkFontSelection *fontsel)
269 GtkWidget *scrolled_win;
270 GtkWidget *text_frame;
272 GtkWidget *table, *label;
273 GtkWidget *font_label, *style_label;
275 GtkTreeViewColumn *column;
276 GList *focus_chain = NULL;
278 gtk_widget_push_composite_child ();
280 fontsel->size = 12 * PANGO_SCALE;
282 /* Create the table of font, style & size. */
283 table = gtk_table_new (3, 3, FALSE);
284 gtk_widget_show (table);
285 gtk_table_set_col_spacings (GTK_TABLE (table), 8);
286 gtk_box_pack_start (GTK_BOX (fontsel), table, TRUE, TRUE, 0);
288 fontsel->font_entry = gtk_entry_new ();
289 gtk_entry_set_editable (GTK_ENTRY (fontsel->font_entry), FALSE);
290 gtk_widget_set_usize (fontsel->font_entry, 20, -1);
291 /* gtk_widget_show (fontsel->font_entry); */
292 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
295 fontsel->font_style_entry = gtk_entry_new ();
296 gtk_entry_set_editable (GTK_ENTRY (fontsel->font_style_entry), FALSE);
297 gtk_widget_set_usize (fontsel->font_style_entry, 20, -1);
298 /* gtk_widget_show (fontsel->font_style_entry); */
299 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
302 fontsel->size_entry = gtk_entry_new ();
303 gtk_widget_set_usize (fontsel->size_entry, 20, -1);
304 gtk_widget_show (fontsel->size_entry);
305 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
307 gtk_signal_connect (GTK_OBJECT (fontsel->size_entry), "activate",
308 (GtkSignalFunc) gtk_font_selection_size_activate,
311 font_label = gtk_label_new_with_mnemonic (_("_Family:"));
312 gtk_misc_set_alignment (GTK_MISC (font_label), 0.0, 0.5);
313 gtk_widget_show (font_label);
314 gtk_table_attach (GTK_TABLE (table), font_label, 0, 1, 0, 1,
317 style_label = gtk_label_new_with_mnemonic (_("_Style:"));
318 gtk_misc_set_alignment (GTK_MISC (style_label), 0.0, 0.5);
319 gtk_widget_show (style_label);
320 gtk_table_attach (GTK_TABLE (table), style_label, 1, 2, 0, 1,
323 label = gtk_label_new_with_mnemonic (_("Si_ze:"));
324 gtk_label_set_mnemonic_widget (GTK_LABEL (label),
325 fontsel->size_entry);
326 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
327 gtk_widget_show (label);
328 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
332 /* Create the lists */
334 model = gtk_list_store_new (2,
335 G_TYPE_OBJECT, /* FAMILY_COLUMN */
336 G_TYPE_STRING); /* FAMILY_NAME_COLUMN */
337 fontsel->family_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
338 g_object_unref (model);
340 column = gtk_tree_view_column_new_with_attributes ("Family",
341 gtk_cell_renderer_text_new (),
342 "text", FAMILY_NAME_COLUMN,
344 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
345 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->family_list), column);
347 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->family_list), FALSE);
348 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)),
349 GTK_SELECTION_BROWSE);
351 gtk_label_set_mnemonic_widget (GTK_LABEL (font_label), fontsel->family_list);
353 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
354 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
355 gtk_widget_set_usize (scrolled_win, FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
356 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->family_list);
357 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
358 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
359 gtk_widget_show (fontsel->family_list);
360 gtk_widget_show (scrolled_win);
362 gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 1, 3,
363 GTK_EXPAND | GTK_FILL,
364 GTK_EXPAND | GTK_FILL, 0, 0);
365 focus_chain = g_list_append (focus_chain, scrolled_win);
367 model = gtk_list_store_new (2,
368 G_TYPE_OBJECT, /* FACE_COLUMN */
369 G_TYPE_STRING); /* FACE_NAME_COLUMN */
370 fontsel->face_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
371 g_object_unref (model);
373 gtk_label_set_mnemonic_widget (GTK_LABEL (style_label), fontsel->face_list);
375 column = gtk_tree_view_column_new_with_attributes ("Face",
376 gtk_cell_renderer_text_new (),
377 "text", FACE_NAME_COLUMN,
379 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
380 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->face_list), column);
382 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->face_list), FALSE);
383 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)),
384 GTK_SELECTION_BROWSE);
386 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
387 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
388 gtk_widget_set_usize (scrolled_win, FONT_STYLE_LIST_WIDTH, FONT_LIST_HEIGHT);
389 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->face_list);
390 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
391 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
392 gtk_widget_show (fontsel->face_list);
393 gtk_widget_show (scrolled_win);
394 gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 1, 3,
395 GTK_EXPAND | GTK_FILL,
396 GTK_EXPAND | GTK_FILL, 0, 0);
397 focus_chain = g_list_append (focus_chain, scrolled_win);
399 focus_chain = g_list_append (focus_chain, fontsel->size_entry);
401 model = gtk_list_store_new (1, G_TYPE_INT);
402 fontsel->size_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
403 g_object_unref (model);
405 column = gtk_tree_view_column_new_with_attributes ("Size",
406 gtk_cell_renderer_text_new (),
409 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
410 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->size_list), column);
412 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->size_list), FALSE);
413 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)),
414 GTK_SELECTION_BROWSE);
416 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
417 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
418 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_list);
419 gtk_widget_set_usize (scrolled_win, -1, FONT_LIST_HEIGHT);
420 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
421 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
422 gtk_widget_show (fontsel->size_list);
423 gtk_widget_show (scrolled_win);
424 gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
425 GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
426 focus_chain = g_list_append (focus_chain, scrolled_win);
428 gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
429 g_list_free (focus_chain);
431 /* Insert the fonts. */
432 gtk_font_selection_show_available_fonts (fontsel);
434 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)), "changed",
435 G_CALLBACK (gtk_font_selection_select_font), fontsel);
437 gtk_signal_connect_after (GTK_OBJECT (fontsel->family_list), "map",
438 GTK_SIGNAL_FUNC (gtk_font_selection_scroll_on_map),
441 gtk_font_selection_show_available_styles (fontsel);
443 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)), "changed",
444 G_CALLBACK (gtk_font_selection_select_style), fontsel);
446 gtk_font_selection_show_available_sizes (fontsel, TRUE);
448 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)), "changed",
449 G_CALLBACK (gtk_font_selection_select_size), fontsel);
451 /* create the text entry widget */
452 label = gtk_label_new_with_mnemonic (_("_Preview:"));
453 gtk_widget_show (label);
455 text_frame = gtk_frame_new (NULL);
456 gtk_frame_set_label_widget (GTK_FRAME (text_frame), label);
458 gtk_widget_show (text_frame);
459 gtk_frame_set_shadow_type (GTK_FRAME (text_frame), GTK_SHADOW_ETCHED_IN);
460 gtk_box_pack_start (GTK_BOX (fontsel), text_frame,
463 /* This is just used to get a 4-pixel space around the preview entry. */
464 text_box = gtk_hbox_new (FALSE, 0);
465 gtk_widget_show (text_box);
466 gtk_container_add (GTK_CONTAINER (text_frame), text_box);
467 gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
469 fontsel->preview_entry = gtk_entry_new ();
470 gtk_label_set_mnemonic_widget (GTK_LABEL (label), fontsel->preview_entry);
472 gtk_widget_show (fontsel->preview_entry);
473 gtk_signal_connect (GTK_OBJECT (fontsel->preview_entry), "changed",
474 (GtkSignalFunc) gtk_font_selection_preview_changed,
476 gtk_widget_set_usize (fontsel->preview_entry, -1, INITIAL_PREVIEW_HEIGHT);
477 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
480 gtk_font_selection_update_preview (fontsel);
482 gtk_widget_pop_composite_child();
486 gtk_font_selection_new ()
488 GtkFontSelection *fontsel;
490 fontsel = gtk_type_new (GTK_TYPE_FONT_SELECTION);
492 return GTK_WIDGET (fontsel);
496 gtk_font_selection_finalize (GObject *object)
498 GtkFontSelection *fontsel;
500 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
502 fontsel = GTK_FONT_SELECTION (object);
505 gdk_font_unref (fontsel->font);
507 if (G_OBJECT_CLASS (font_selection_parent_class)->finalize)
508 (* G_OBJECT_CLASS (font_selection_parent_class)->finalize) (object);
512 gtk_font_selection_preview_changed (GtkWidget *entry,
513 GtkFontSelection *fontsel)
515 g_object_notify (G_OBJECT (fontsel), "preview_text");
519 scroll_to_selection (GtkTreeView *tree_view)
521 GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
525 if (gtk_tree_selection_get_selected (selection, &model, &iter))
527 GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
528 gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5);
529 gtk_tree_path_free (path);
534 set_cursor_to_iter (GtkTreeView *view,
537 GtkTreeModel *model = gtk_tree_view_get_model (view);
538 GtkTreePath *path = gtk_tree_model_get_path (model, iter);
540 gtk_tree_view_set_cursor (view, path, 0, FALSE);
542 gtk_tree_path_free (path);
545 /* This is called when the list is mapped. Here we scroll to the current
546 font if necessary. */
548 gtk_font_selection_scroll_on_map (GtkWidget *widget,
551 GtkFontSelection *fontsel;
554 g_message ("In expose_list\n");
556 fontsel = GTK_FONT_SELECTION (data);
558 /* Try to scroll the font family list to the selected item */
559 scroll_to_selection (GTK_TREE_VIEW (fontsel->family_list));
561 /* Try to scroll the font family list to the selected item */
562 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
564 /* Try to scroll the font family list to the selected item */
565 scroll_to_selection (GTK_TREE_VIEW (fontsel->size_list));
568 /* This is called when a family is selected in the list. */
570 gtk_font_selection_select_font (GtkTreeSelection *selection,
573 GtkFontSelection *fontsel;
576 const gchar *family_name;
578 fontsel = GTK_FONT_SELECTION (data);
580 if (gtk_tree_selection_get_selected (selection, &model, &iter))
582 PangoFontFamily *family;
584 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
585 if (fontsel->family != family)
587 fontsel->family = family;
589 family_name = pango_font_family_get_name (fontsel->family);
591 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
593 gtk_font_selection_show_available_styles (fontsel);
594 gtk_font_selection_select_best_style (fontsel, TRUE);
597 g_object_unref (family);
602 cmp_families (const void *a, const void *b)
604 const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
605 const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
607 return strcmp (a_name, b_name);
611 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
614 PangoFontFamily **families;
615 PangoFontFamily *match_family = NULL;
617 GtkTreeIter match_row;
619 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list)));
621 pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
622 &families, &n_families);
623 qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families);
625 gtk_list_store_clear (model);
627 for (i=0; i<n_families; i++)
629 const gchar *name = pango_font_family_get_name (families[i]);
632 gtk_list_store_append (model, &iter);
633 gtk_list_store_set (model, &iter,
634 FAMILY_COLUMN, families[i],
635 FAMILY_NAME_COLUMN, name,
638 if (i == 0 || !g_ascii_strcasecmp (name, "sans"))
640 match_family = families[i];
645 fontsel->family = match_family;
648 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &match_row);
649 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry),
650 pango_font_family_get_name (match_family));
657 compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
659 int val = strcmp (pango_font_description_get_family (a), pango_font_description_get_family (b));
663 if (pango_font_description_get_weight (a) != pango_font_description_get_weight (b))
664 return pango_font_description_get_weight (a) - pango_font_description_get_weight (b);
666 if (pango_font_description_get_style (a) != pango_font_description_get_style (b))
667 return pango_font_description_get_style (a) - pango_font_description_get_style (b);
669 if (pango_font_description_get_stretch (a) != pango_font_description_get_stretch (b))
670 return pango_font_description_get_stretch (a) - pango_font_description_get_stretch (b);
672 if (pango_font_description_get_variant (a) != pango_font_description_get_variant (b))
673 return pango_font_description_get_variant (a) - pango_font_description_get_variant (b);
679 faces_sort_func (const void *a, const void *b)
681 PangoFontDescription *desc_a = pango_font_face_describe (*(PangoFontFace **)a);
682 PangoFontDescription *desc_b = pango_font_face_describe (*(PangoFontFace **)b);
684 int ord = compare_font_descriptions (desc_a, desc_b);
686 pango_font_description_free (desc_a);
687 pango_font_description_free (desc_b);
693 font_description_style_equal (const PangoFontDescription *a,
694 const PangoFontDescription *b)
696 return (pango_font_description_get_weight (a) == pango_font_description_get_weight (b) &&
697 pango_font_description_get_style (a) == pango_font_description_get_style (b) &&
698 pango_font_description_get_stretch (a) == pango_font_description_get_stretch (b) &&
699 pango_font_description_get_variant (a) == pango_font_description_get_variant (b));
702 /* This fills the font style list with all the possible style combinations
703 for the current font family. */
705 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
708 PangoFontFace **faces;
709 PangoFontDescription *old_desc;
711 GtkTreeIter match_row;
712 PangoFontFace *match_face = NULL;
714 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list)));
717 old_desc = pango_font_face_describe (fontsel->face);
721 pango_font_family_list_faces (fontsel->family, &faces, &n_faces);
722 qsort (faces, n_faces, sizeof (PangoFontFace *), faces_sort_func);
724 gtk_list_store_clear (model);
726 for (i=0; i < n_faces; i++)
729 const gchar *str = pango_font_face_get_face_name (faces[i]);
731 gtk_list_store_append (model, &iter);
732 gtk_list_store_set (model, &iter,
733 FACE_COLUMN, faces[i],
734 FACE_NAME_COLUMN, str,
740 match_face = faces[i];
744 PangoFontDescription *tmp_desc = pango_font_face_describe (faces[i]);
746 if (font_description_style_equal (tmp_desc, old_desc))
749 match_face = faces[i];
752 pango_font_description_free (tmp_desc);
757 pango_font_description_free (old_desc);
759 fontsel->face = match_face;
762 const gchar *str = pango_font_face_get_face_name (fontsel->face);
764 gtk_entry_set_text (GTK_ENTRY (fontsel->font_style_entry), str);
765 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_row);
771 /* This selects a style when the user selects a font. It just uses the first
772 available style at present. I was thinking of trying to maintain the
773 selected style, e.g. bold italic, when the user selects different fonts.
774 However, the interface is so easy to use now I'm not sure it's worth it.
775 Note: This will load a font. */
777 gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
783 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
785 if (gtk_tree_model_get_iter_first (model, &iter))
787 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &iter);
788 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
791 gtk_font_selection_show_available_sizes (fontsel, FALSE);
792 gtk_font_selection_select_best_size (fontsel);
796 /* This is called when a style is selected in the list. */
798 gtk_font_selection_select_style (GtkTreeSelection *selection,
801 GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
805 if (gtk_tree_selection_get_selected (selection, &model, &iter))
809 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
810 fontsel->face = face;
812 g_object_unref (face);
815 gtk_font_selection_show_available_sizes (fontsel, FALSE);
816 gtk_font_selection_select_best_size (fontsel);
820 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel,
825 GtkTreeSelection *selection;
829 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
830 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
832 /* Insert the standard font sizes */
835 gtk_list_store_clear (model);
837 for (i = 0; i < G_N_ELEMENTS (font_sizes); i++)
841 gtk_list_store_append (model, &iter);
842 gtk_list_store_set (model, &iter, SIZE_COLUMN, font_sizes[i], -1);
844 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
845 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
851 gboolean found = FALSE;
853 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
854 for (i = 0; i < G_N_ELEMENTS (font_sizes) && !found; i++)
856 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
858 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
862 gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
867 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
868 gtk_tree_selection_unselect_all (selection);
872 /* Set the entry to the new size, rounding to 1 digit,
873 * trimming of trailing 0's and a trailing period
875 sprintf (buffer, "%.1f", fontsel->size / (1.0 * PANGO_SCALE));
876 if (strchr (buffer, '.'))
878 p = buffer + strlen (buffer) - 1;
886 /* Compare, to avoid moving the cursor unecessarily */
887 if (strcmp (gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry)), buffer) != 0)
888 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
892 gtk_font_selection_select_best_size (GtkFontSelection *fontsel)
894 gtk_font_selection_load_font (fontsel);
898 gtk_font_selection_set_size (GtkFontSelection *fontsel,
901 if (fontsel->size != new_size)
903 fontsel->size = new_size;
905 gtk_font_selection_show_available_sizes (fontsel, FALSE);
906 gtk_font_selection_load_font (fontsel);
910 /* If the user hits return in the font size entry, we change to the new font
913 gtk_font_selection_size_activate (GtkWidget *w,
916 GtkFontSelection *fontsel;
920 fontsel = GTK_FONT_SELECTION (data);
922 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
923 new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
925 gtk_font_selection_set_size (fontsel, new_size);
928 /* This is called when a size is selected in the list. */
930 gtk_font_selection_select_size (GtkTreeSelection *selection,
933 GtkFontSelection *fontsel;
938 fontsel = GTK_FONT_SELECTION (data);
940 if (gtk_tree_selection_get_selected (selection, &model, &iter))
942 gtk_tree_model_get (model, &iter, SIZE_COLUMN, &new_size, -1);
943 gtk_font_selection_set_size (fontsel, new_size * PANGO_SCALE);
948 gtk_font_selection_load_font (GtkFontSelection *fontsel)
951 gdk_font_unref (fontsel->font);
952 fontsel->font = NULL;
954 gtk_font_selection_update_preview (fontsel);
957 static PangoFontDescription *
958 gtk_font_selection_get_font_description (GtkFontSelection *fontsel)
960 PangoFontDescription *font_desc = pango_font_face_describe (fontsel->face);
961 pango_font_description_set_size (font_desc, fontsel->size);
966 /* This sets the font in the preview entry to the selected font, and tries to
967 make sure that the preview entry is a reasonable size, i.e. so that the
968 text can be seen with a bit of space to spare. But it tries to avoid
969 resizing the entry every time the font changes.
970 This also used to shrink the preview if the font size was decreased, but
971 that made it awkward if the user wanted to resize the window themself. */
973 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
975 GtkRcStyle *rc_style;
977 GtkRequisition old_requisition;
978 GtkWidget *preview_entry = fontsel->preview_entry;
981 gtk_widget_get_child_requisition (preview_entry, &old_requisition);
983 rc_style = gtk_rc_style_new ();
984 rc_style->font_desc = gtk_font_selection_get_font_description (fontsel);
986 gtk_widget_modify_style (preview_entry, rc_style);
987 gtk_rc_style_unref (rc_style);
989 gtk_widget_size_request (preview_entry, NULL);
991 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
992 new_height = CLAMP (preview_entry->requisition.height, INITIAL_PREVIEW_HEIGHT, MAX_PREVIEW_HEIGHT);
994 if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
995 gtk_widget_set_usize (preview_entry, -1, new_height);
997 /* This sets the preview text, if it hasn't been set already. */
998 text = gtk_entry_get_text (GTK_ENTRY (preview_entry));
999 if (strlen (text) == 0)
1000 gtk_entry_set_text (GTK_ENTRY (preview_entry), PREVIEW_TEXT);
1001 gtk_entry_set_position (GTK_ENTRY (preview_entry), 0);
1004 /*****************************************************************************
1005 * These functions are the main public interface for getting/setting the font.
1006 *****************************************************************************/
1009 gtk_font_selection_get_font (GtkFontSelection *fontsel)
1013 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1014 fontsel->font = gdk_font_from_description (font_desc);
1015 pango_font_description_free (font_desc);
1018 return fontsel->font;
1023 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
1027 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1028 result = pango_font_description_to_string (font_desc);
1029 pango_font_description_free (font_desc);
1035 /* This sets the current font, selecting the appropriate list rows.
1036 First we check the fontname is valid and try to find the font family
1037 - i.e. the name in the main list. If we can't find that, then just return.
1038 Next we try to set each of the properties according to the fontname.
1039 Finally we select the font family & style in the lists. */
1041 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
1042 const gchar *fontname)
1044 PangoFontFamily *new_family = NULL;
1045 PangoFontFace *new_face = NULL;
1046 PangoFontFace *fallback_face = NULL;
1047 PangoFontDescription *new_desc;
1048 GtkTreeModel *model;
1050 GtkTreeIter match_iter;
1053 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
1055 new_desc = pango_font_description_from_string (fontname);
1057 /* Check to make sure that this is in the list of allowed fonts */
1059 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list));
1060 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1062 valid = gtk_tree_model_iter_next (model, &iter))
1064 PangoFontFamily *family;
1066 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
1068 if (g_ascii_strcasecmp (pango_font_family_get_name (family),
1069 pango_font_description_get_family (new_desc)) == 0)
1070 new_family = family;
1072 g_object_unref (family);
1081 fontsel->family = new_family;
1082 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &iter);
1083 gtk_font_selection_show_available_styles (fontsel);
1085 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1086 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1088 valid = gtk_tree_model_iter_next (model, &iter))
1090 PangoFontFace *face;
1091 PangoFontDescription *tmp_desc;
1093 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
1094 tmp_desc = pango_font_face_describe (face);
1096 if (font_description_style_equal (tmp_desc, new_desc))
1101 fallback_face = face;
1105 pango_font_description_free (tmp_desc);
1106 g_object_unref (face);
1116 new_face = fallback_face;
1118 fontsel->face = new_face;
1119 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_iter);
1121 gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
1123 g_object_freeze_notify (G_OBJECT (fontsel));
1124 g_object_notify (G_OBJECT (fontsel), "font_name");
1125 g_object_notify (G_OBJECT (fontsel), "font");
1126 g_object_thaw_notify (G_OBJECT (fontsel));
1128 pango_font_description_free (new_desc);
1134 /* This returns the text in the preview entry. You should copy the returned
1135 text if you need it. */
1136 G_CONST_RETURN gchar*
1137 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
1139 return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
1143 /* This sets the text in the preview entry. */
1145 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
1148 gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
1151 /*****************************************************************************
1152 * GtkFontSelectionDialog
1153 *****************************************************************************/
1156 gtk_font_selection_dialog_get_type (void)
1158 static GtkType font_selection_dialog_type = 0;
1160 if (!font_selection_dialog_type)
1162 GtkTypeInfo fontsel_diag_info =
1164 "GtkFontSelectionDialog",
1165 sizeof (GtkFontSelectionDialog),
1166 sizeof (GtkFontSelectionDialogClass),
1167 (GtkClassInitFunc) gtk_font_selection_dialog_class_init,
1168 (GtkObjectInitFunc) gtk_font_selection_dialog_init,
1169 /* reserved_1 */ NULL,
1170 /* reserved_2 */ NULL,
1171 (GtkClassInitFunc) NULL,
1174 font_selection_dialog_type = gtk_type_unique (GTK_TYPE_DIALOG,
1175 &fontsel_diag_info);
1178 return font_selection_dialog_type;
1182 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1184 GtkObjectClass *object_class;
1186 object_class = (GtkObjectClass*) klass;
1188 font_selection_dialog_parent_class = gtk_type_class (GTK_TYPE_DIALOG);
1192 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1196 gtk_widget_push_composite_child ();
1198 dialog = GTK_DIALOG (fontseldiag);
1200 fontseldiag->dialog_width = -1;
1201 fontseldiag->auto_resize = TRUE;
1203 gtk_widget_set_events (GTK_WIDGET (fontseldiag), GDK_STRUCTURE_MASK);
1204 gtk_signal_connect (GTK_OBJECT (fontseldiag), "configure_event",
1205 (GtkSignalFunc) gtk_font_selection_dialog_on_configure,
1208 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
1209 gtk_window_set_policy (GTK_WINDOW (fontseldiag), FALSE, TRUE, TRUE);
1211 fontseldiag->main_vbox = dialog->vbox;
1213 fontseldiag->fontsel = gtk_font_selection_new ();
1214 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 4);
1215 gtk_widget_show (fontseldiag->fontsel);
1216 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
1217 fontseldiag->fontsel, TRUE, TRUE, 0);
1219 /* Create the action area */
1220 fontseldiag->action_area = dialog->action_area;
1222 fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1224 GTK_RESPONSE_CANCEL);
1226 fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1228 GTK_RESPONSE_APPLY);
1229 gtk_widget_hide (fontseldiag->apply_button);
1231 fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1234 gtk_widget_grab_default (fontseldiag->ok_button);
1236 gtk_window_set_title (GTK_WINDOW (fontseldiag),
1237 _("Font Selection"));
1239 gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
1241 gtk_widget_pop_composite_child ();
1245 gtk_font_selection_dialog_new (const gchar *title)
1247 GtkFontSelectionDialog *fontseldiag;
1249 fontseldiag = gtk_type_new (GTK_TYPE_FONT_SELECTION_DIALOG);
1252 gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1254 return GTK_WIDGET (fontseldiag);
1258 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1260 return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1264 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1266 return gtk_font_selection_get_font (GTK_FONT_SELECTION (fsd->fontsel));
1270 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1271 const gchar *fontname)
1273 return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1276 G_CONST_RETURN gchar*
1277 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1279 return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1283 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1286 gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);
1290 /* This turns auto-shrink off if the user resizes the width of the dialog.
1291 It also turns it back on again if the user resizes it back to its normal
1294 gtk_font_selection_dialog_on_configure (GtkWidget *widget,
1295 GdkEventConfigure *event,
1296 GtkFontSelectionDialog *fsd)
1298 /* This sets the initial width. */
1299 if (fsd->dialog_width == -1)
1300 fsd->dialog_width = event->width;
1301 else if (fsd->auto_resize && fsd->dialog_width != event->width)
1303 fsd->auto_resize = FALSE;
1304 gtk_window_set_policy (GTK_WINDOW (fsd), FALSE, TRUE, FALSE);
1306 else if (!fsd->auto_resize && fsd->dialog_width == event->width)
1308 fsd->auto_resize = TRUE;
1309 gtk_window_set_policy (GTK_WINDOW (fsd), FALSE, TRUE, TRUE);