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/.
34 #include <glib/gprintf.h>
40 #include "gdk/gdkkeysyms.h"
42 #include "gtkfontsel.h"
44 #include "gtkbutton.h"
45 #include "gtkcellrenderertext.h"
51 #include "gtkliststore.h"
55 #include "gtktreeselection.h"
56 #include "gtktreeview.h"
58 #include "gtkscrolledwindow.h"
60 #include "gtkaccessible.h"
61 #include "gtkprivate.h"
64 /* We don't enable the font and style entries because they don't add
65 * much in terms of visible effect and have a weird effect on keynav.
66 * the Windows font selector has entries similarly positioned but they
67 * act in conjunction with the associated lists to form a single focus
70 #undef INCLUDE_FONT_ENTRIES
72 /* This is the default text shown in the preview entry, though the user
73 can set it. Remember that some fonts only have capital letters. */
74 #define PREVIEW_TEXT N_("abcdefghijk ABCDEFGHIJK")
76 /* This is the initial and maximum height of the preview entry (it expands
77 when large font sizes are selected). Initial height is also the minimum. */
78 #define INITIAL_PREVIEW_HEIGHT 44
79 #define MAX_PREVIEW_HEIGHT 300
81 /* These are the sizes of the font, style & size lists. */
82 #define FONT_LIST_HEIGHT 136
83 #define FONT_LIST_WIDTH 190
84 #define FONT_STYLE_LIST_WIDTH 170
85 #define FONT_SIZE_LIST_WIDTH 60
87 /* These are what we use as the standard font sizes, for the size list.
89 static const guint16 font_sizes[] = {
90 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
91 32, 36, 40, 48, 56, 64, 72
116 static void gtk_font_selection_class_init (GtkFontSelectionClass *klass);
117 static void gtk_font_selection_set_property (GObject *object,
121 static void gtk_font_selection_get_property (GObject *object,
125 static void gtk_font_selection_init (GtkFontSelection *fontsel);
126 static void gtk_font_selection_finalize (GObject *object);
127 static void gtk_font_selection_screen_changed (GtkWidget *widget,
128 GdkScreen *previous_screen);
130 /* These are the callbacks & related functions. */
131 static void gtk_font_selection_select_font (GtkTreeSelection *selection,
133 static void gtk_font_selection_show_available_fonts (GtkFontSelection *fs);
135 static void gtk_font_selection_show_available_styles (GtkFontSelection *fs);
136 static void gtk_font_selection_select_best_style (GtkFontSelection *fs,
138 static void gtk_font_selection_select_style (GtkTreeSelection *selection,
141 static void gtk_font_selection_select_best_size (GtkFontSelection *fs);
142 static void gtk_font_selection_show_available_sizes (GtkFontSelection *fs,
143 gboolean first_time);
144 static void gtk_font_selection_size_activate (GtkWidget *w,
146 static gboolean gtk_font_selection_size_focus_out (GtkWidget *w,
147 GdkEventFocus *event,
149 static void gtk_font_selection_select_size (GtkTreeSelection *selection,
152 static void gtk_font_selection_scroll_on_map (GtkWidget *w,
155 static void gtk_font_selection_preview_changed (GtkWidget *entry,
156 GtkFontSelection *fontsel);
158 /* Misc. utility functions. */
159 static void gtk_font_selection_load_font (GtkFontSelection *fs);
160 static void gtk_font_selection_update_preview (GtkFontSelection *fs);
162 static GdkFont* gtk_font_selection_get_font_internal (GtkFontSelection *fontsel);
164 /* FontSelectionDialog */
165 static void gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass);
166 static void gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag);
168 static GtkVBoxClass *font_selection_parent_class = NULL;
169 static GtkWindowClass *font_selection_dialog_parent_class = NULL;
173 gtk_font_selection_get_type (void)
175 static GType font_selection_type = 0;
177 if (!font_selection_type)
179 static const GTypeInfo fontsel_type_info =
181 sizeof (GtkFontSelectionClass),
182 NULL, /* base_init */
183 NULL, /* base_finalize */
184 (GClassInitFunc) gtk_font_selection_class_init,
185 NULL, /* class_finalize */
186 NULL, /* class_data */
187 sizeof (GtkFontSelection),
189 (GInstanceInitFunc) gtk_font_selection_init,
192 font_selection_type =
193 g_type_register_static (GTK_TYPE_VBOX, I_("GtkFontSelection"),
194 &fontsel_type_info, 0);
197 return font_selection_type;
201 gtk_font_selection_class_init (GtkFontSelectionClass *klass)
203 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
204 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
206 font_selection_parent_class = g_type_class_peek_parent (klass);
208 gobject_class->set_property = gtk_font_selection_set_property;
209 gobject_class->get_property = gtk_font_selection_get_property;
211 widget_class->screen_changed = gtk_font_selection_screen_changed;
213 g_object_class_install_property (gobject_class,
215 g_param_spec_string ("font-name",
217 P_("The X string that represents this font"),
219 GTK_PARAM_READWRITE));
220 g_object_class_install_property (gobject_class,
222 g_param_spec_boxed ("font",
224 P_("The GdkFont that is currently selected"),
226 GTK_PARAM_READABLE));
227 g_object_class_install_property (gobject_class,
229 g_param_spec_string ("preview-text",
231 P_("The text to display in order to demonstrate the selected font"),
233 GTK_PARAM_READWRITE));
234 gobject_class->finalize = gtk_font_selection_finalize;
238 gtk_font_selection_set_property (GObject *object,
243 GtkFontSelection *fontsel;
245 fontsel = GTK_FONT_SELECTION (object);
250 gtk_font_selection_set_font_name (fontsel, g_value_get_string (value));
252 case PROP_PREVIEW_TEXT:
253 gtk_font_selection_set_preview_text (fontsel, g_value_get_string (value));
256 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
261 static void gtk_font_selection_get_property (GObject *object,
266 GtkFontSelection *fontsel;
268 fontsel = GTK_FONT_SELECTION (object);
273 g_value_set_string (value, gtk_font_selection_get_font_name (fontsel));
276 g_value_set_object (value, gtk_font_selection_get_font_internal (fontsel));
278 case PROP_PREVIEW_TEXT:
279 g_value_set_string (value, gtk_font_selection_get_preview_text (fontsel));
282 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
287 /* Handles key press events on the lists, so that we can trap Enter to
288 * activate the default button on our own.
291 list_row_activated (GtkWidget *widget)
295 window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
296 if (!GTK_WIDGET_TOPLEVEL (window))
300 && widget != window->default_widget
301 && !(widget == window->focus_widget &&
302 (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget))))
304 gtk_window_activate_default (window);
311 gtk_font_selection_init (GtkFontSelection *fontsel)
313 GtkWidget *scrolled_win;
314 GtkWidget *text_frame;
316 GtkWidget *table, *label;
317 GtkWidget *font_label, *style_label;
319 GtkTreeViewColumn *column;
320 GList *focus_chain = NULL;
323 gtk_widget_push_composite_child ();
325 fontsel->size = 12 * PANGO_SCALE;
327 /* Create the table of font, style & size. */
328 table = gtk_table_new (3, 3, FALSE);
329 gtk_widget_show (table);
330 gtk_table_set_col_spacings (GTK_TABLE (table), 8);
331 gtk_box_pack_start (GTK_BOX (fontsel), table, TRUE, TRUE, 0);
333 #ifdef INCLUDE_FONT_ENTRIES
334 fontsel->font_entry = gtk_entry_new ();
335 gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_entry), FALSE);
336 gtk_widget_set_size_request (fontsel->font_entry, 20, -1);
337 gtk_widget_show (fontsel->font_entry);
338 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
341 fontsel->font_style_entry = gtk_entry_new ();
342 gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_style_entry), FALSE);
343 gtk_widget_set_size_request (fontsel->font_style_entry, 20, -1);
344 gtk_widget_show (fontsel->font_style_entry);
345 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
347 #endif /* INCLUDE_FONT_ENTRIES */
349 fontsel->size_entry = gtk_entry_new ();
350 gtk_widget_set_size_request (fontsel->size_entry, 20, -1);
351 gtk_widget_show (fontsel->size_entry);
352 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
354 g_signal_connect (fontsel->size_entry, "activate",
355 G_CALLBACK (gtk_font_selection_size_activate),
357 g_signal_connect_after (fontsel->size_entry, "focus_out_event",
358 G_CALLBACK (gtk_font_selection_size_focus_out),
361 font_label = gtk_label_new_with_mnemonic (_("_Family:"));
362 gtk_misc_set_alignment (GTK_MISC (font_label), 0.0, 0.5);
363 gtk_widget_show (font_label);
364 gtk_table_attach (GTK_TABLE (table), font_label, 0, 1, 0, 1,
367 style_label = gtk_label_new_with_mnemonic (_("_Style:"));
368 gtk_misc_set_alignment (GTK_MISC (style_label), 0.0, 0.5);
369 gtk_widget_show (style_label);
370 gtk_table_attach (GTK_TABLE (table), style_label, 1, 2, 0, 1,
373 label = gtk_label_new_with_mnemonic (_("Si_ze:"));
374 gtk_label_set_mnemonic_widget (GTK_LABEL (label),
375 fontsel->size_entry);
376 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
377 gtk_widget_show (label);
378 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
382 /* Create the lists */
384 model = gtk_list_store_new (2,
385 G_TYPE_OBJECT, /* FAMILY_COLUMN */
386 G_TYPE_STRING); /* FAMILY_NAME_COLUMN */
387 fontsel->family_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
388 g_object_unref (model);
390 g_signal_connect (fontsel->family_list, "row-activated",
391 G_CALLBACK (list_row_activated), fontsel);
393 column = gtk_tree_view_column_new_with_attributes ("Family",
394 gtk_cell_renderer_text_new (),
395 "text", FAMILY_NAME_COLUMN,
397 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
398 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->family_list), column);
400 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->family_list), FALSE);
401 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)),
402 GTK_SELECTION_BROWSE);
404 gtk_label_set_mnemonic_widget (GTK_LABEL (font_label), fontsel->family_list);
406 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
407 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
408 gtk_widget_set_size_request (scrolled_win,
409 FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
410 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->family_list);
411 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
412 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
413 gtk_widget_show (fontsel->family_list);
414 gtk_widget_show (scrolled_win);
416 gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 1, 3,
417 GTK_EXPAND | GTK_FILL,
418 GTK_EXPAND | GTK_FILL, 0, 0);
419 focus_chain = g_list_append (focus_chain, scrolled_win);
421 model = gtk_list_store_new (2,
422 G_TYPE_OBJECT, /* FACE_COLUMN */
423 G_TYPE_STRING); /* FACE_NAME_COLUMN */
424 fontsel->face_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
425 g_object_unref (model);
426 g_signal_connect (fontsel->face_list, "row-activated",
427 G_CALLBACK (list_row_activated), fontsel);
429 gtk_label_set_mnemonic_widget (GTK_LABEL (style_label), fontsel->face_list);
431 column = gtk_tree_view_column_new_with_attributes ("Face",
432 gtk_cell_renderer_text_new (),
433 "text", FACE_NAME_COLUMN,
435 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
436 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->face_list), column);
438 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->face_list), FALSE);
439 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)),
440 GTK_SELECTION_BROWSE);
442 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
443 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
444 gtk_widget_set_size_request (scrolled_win,
445 FONT_STYLE_LIST_WIDTH, FONT_LIST_HEIGHT);
446 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->face_list);
447 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
448 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
449 gtk_widget_show (fontsel->face_list);
450 gtk_widget_show (scrolled_win);
451 gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 1, 3,
452 GTK_EXPAND | GTK_FILL,
453 GTK_EXPAND | GTK_FILL, 0, 0);
454 focus_chain = g_list_append (focus_chain, scrolled_win);
456 focus_chain = g_list_append (focus_chain, fontsel->size_entry);
458 model = gtk_list_store_new (1, G_TYPE_INT);
459 fontsel->size_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
460 g_object_unref (model);
461 g_signal_connect (fontsel->size_list, "row-activated",
462 G_CALLBACK (list_row_activated), fontsel);
464 column = gtk_tree_view_column_new_with_attributes ("Size",
465 gtk_cell_renderer_text_new (),
468 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
469 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->size_list), column);
471 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->size_list), FALSE);
472 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)),
473 GTK_SELECTION_BROWSE);
475 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
476 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
477 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_list);
478 gtk_widget_set_size_request (scrolled_win, -1, FONT_LIST_HEIGHT);
479 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
480 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
481 gtk_widget_show (fontsel->size_list);
482 gtk_widget_show (scrolled_win);
483 gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
484 GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
485 focus_chain = g_list_append (focus_chain, scrolled_win);
487 gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
488 g_list_free (focus_chain);
490 /* Insert the fonts. */
491 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)), "changed",
492 G_CALLBACK (gtk_font_selection_select_font), fontsel);
494 g_signal_connect_after (fontsel->family_list, "map",
495 G_CALLBACK (gtk_font_selection_scroll_on_map),
498 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)), "changed",
499 G_CALLBACK (gtk_font_selection_select_style), fontsel);
501 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)), "changed",
502 G_CALLBACK (gtk_font_selection_select_size), fontsel);
503 atk_obj = gtk_widget_get_accessible (fontsel->size_list);
504 if (GTK_IS_ACCESSIBLE (atk_obj))
506 /* Accessibility support is enabled.
507 * Make the label ATK_RELATON_LABEL_FOR for the size list as well.
509 AtkObject *atk_label;
510 AtkRelationSet *relation_set;
511 AtkRelation *relation;
512 AtkObject *obj_array[1];
515 atk_label = gtk_widget_get_accessible (label);
516 relation_set = atk_object_ref_relation_set (atk_obj);
517 relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_LABELLED_BY);
520 array = atk_relation_get_target (relation);
521 g_ptr_array_add (array, atk_label);
525 obj_array[0] = atk_label;
526 relation = atk_relation_new (obj_array, 1, ATK_RELATION_LABELLED_BY);
527 atk_relation_set_add (relation_set, relation);
529 g_object_unref (relation_set);
531 relation_set = atk_object_ref_relation_set (atk_label);
532 relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_LABEL_FOR);
535 array = atk_relation_get_target (relation);
536 g_ptr_array_add (array, atk_obj);
540 obj_array[0] = atk_obj;
541 relation = atk_relation_new (obj_array, 1, ATK_RELATION_LABEL_FOR);
542 atk_relation_set_add (relation_set, relation);
544 g_object_unref (relation_set);
548 /* create the text entry widget */
549 label = gtk_label_new_with_mnemonic (_("_Preview:"));
550 gtk_widget_show (label);
552 text_frame = gtk_frame_new (NULL);
553 gtk_frame_set_label_widget (GTK_FRAME (text_frame), label);
555 gtk_widget_show (text_frame);
556 gtk_frame_set_shadow_type (GTK_FRAME (text_frame), GTK_SHADOW_ETCHED_IN);
557 gtk_box_pack_start (GTK_BOX (fontsel), text_frame,
560 /* This is just used to get a 4-pixel space around the preview entry. */
561 text_box = gtk_hbox_new (FALSE, 0);
562 gtk_widget_show (text_box);
563 gtk_container_add (GTK_CONTAINER (text_frame), text_box);
564 gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
566 fontsel->preview_entry = gtk_entry_new ();
567 gtk_label_set_mnemonic_widget (GTK_LABEL (label), fontsel->preview_entry);
569 gtk_widget_show (fontsel->preview_entry);
570 g_signal_connect (fontsel->preview_entry, "changed",
571 G_CALLBACK (gtk_font_selection_preview_changed), fontsel);
572 gtk_widget_set_size_request (fontsel->preview_entry,
573 -1, INITIAL_PREVIEW_HEIGHT);
574 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
577 gtk_widget_pop_composite_child();
581 gtk_font_selection_new (void)
583 GtkFontSelection *fontsel;
585 fontsel = g_object_new (GTK_TYPE_FONT_SELECTION, NULL);
587 return GTK_WIDGET (fontsel);
591 gtk_font_selection_finalize (GObject *object)
593 GtkFontSelection *fontsel;
595 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
597 fontsel = GTK_FONT_SELECTION (object);
600 gdk_font_unref (fontsel->font);
602 (* G_OBJECT_CLASS (font_selection_parent_class)->finalize) (object);
606 gtk_font_selection_screen_changed (GtkWidget *widget,
607 GdkScreen *previous_screen)
609 GtkFontSelection *fontsel = GTK_FONT_SELECTION (widget);
611 if (gtk_widget_has_screen (GTK_WIDGET (fontsel)))
613 gtk_font_selection_show_available_fonts (fontsel);
614 gtk_font_selection_show_available_sizes (fontsel, TRUE);
615 gtk_font_selection_show_available_styles (fontsel);
620 gtk_font_selection_preview_changed (GtkWidget *entry,
621 GtkFontSelection *fontsel)
623 g_object_notify (G_OBJECT (fontsel), "preview_text");
627 scroll_to_selection (GtkTreeView *tree_view)
629 GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
633 if (gtk_tree_selection_get_selected (selection, &model, &iter))
635 GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
636 gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5);
637 gtk_tree_path_free (path);
642 set_cursor_to_iter (GtkTreeView *view,
645 GtkTreeModel *model = gtk_tree_view_get_model (view);
646 GtkTreePath *path = gtk_tree_model_get_path (model, iter);
648 gtk_tree_view_set_cursor (view, path, NULL, FALSE);
650 gtk_tree_path_free (path);
653 /* This is called when the list is mapped. Here we scroll to the current
654 font if necessary. */
656 gtk_font_selection_scroll_on_map (GtkWidget *widget,
659 GtkFontSelection *fontsel;
662 g_message ("In expose_list\n");
664 fontsel = GTK_FONT_SELECTION (data);
666 /* Try to scroll the font family list to the selected item */
667 scroll_to_selection (GTK_TREE_VIEW (fontsel->family_list));
669 /* Try to scroll the font family list to the selected item */
670 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
672 /* Try to scroll the font family list to the selected item */
673 scroll_to_selection (GTK_TREE_VIEW (fontsel->size_list));
676 /* This is called when a family is selected in the list. */
678 gtk_font_selection_select_font (GtkTreeSelection *selection,
681 GtkFontSelection *fontsel;
684 #ifdef INCLUDE_FONT_ENTRIES
685 const gchar *family_name;
688 fontsel = GTK_FONT_SELECTION (data);
690 if (gtk_tree_selection_get_selected (selection, &model, &iter))
692 PangoFontFamily *family;
694 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
695 if (fontsel->family != family)
697 fontsel->family = family;
699 #ifdef INCLUDE_FONT_ENTRIES
700 family_name = pango_font_family_get_name (fontsel->family);
701 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
704 gtk_font_selection_show_available_styles (fontsel);
705 gtk_font_selection_select_best_style (fontsel, TRUE);
708 g_object_unref (family);
713 cmp_families (const void *a, const void *b)
715 const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
716 const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
718 return g_utf8_collate (a_name, b_name);
722 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
725 PangoFontFamily **families;
726 PangoFontFamily *match_family = NULL;
728 GtkTreeIter match_row;
730 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list)));
732 pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
733 &families, &n_families);
734 qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families);
736 gtk_list_store_clear (model);
738 for (i=0; i<n_families; i++)
740 const gchar *name = pango_font_family_get_name (families[i]);
743 gtk_list_store_append (model, &iter);
744 gtk_list_store_set (model, &iter,
745 FAMILY_COLUMN, families[i],
746 FAMILY_NAME_COLUMN, name,
749 if (i == 0 || !g_ascii_strcasecmp (name, "sans"))
751 match_family = families[i];
756 fontsel->family = match_family;
759 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &match_row);
760 #ifdef INCLUDE_FONT_ENTRIES
761 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry),
762 pango_font_family_get_name (match_family));
763 #endif /* INCLUDE_FONT_ENTRIES */
770 compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
772 int val = strcmp (pango_font_description_get_family (a), pango_font_description_get_family (b));
776 if (pango_font_description_get_weight (a) != pango_font_description_get_weight (b))
777 return pango_font_description_get_weight (a) - pango_font_description_get_weight (b);
779 if (pango_font_description_get_style (a) != pango_font_description_get_style (b))
780 return pango_font_description_get_style (a) - pango_font_description_get_style (b);
782 if (pango_font_description_get_stretch (a) != pango_font_description_get_stretch (b))
783 return pango_font_description_get_stretch (a) - pango_font_description_get_stretch (b);
785 if (pango_font_description_get_variant (a) != pango_font_description_get_variant (b))
786 return pango_font_description_get_variant (a) - pango_font_description_get_variant (b);
792 faces_sort_func (const void *a, const void *b)
794 PangoFontDescription *desc_a = pango_font_face_describe (*(PangoFontFace **)a);
795 PangoFontDescription *desc_b = pango_font_face_describe (*(PangoFontFace **)b);
797 int ord = compare_font_descriptions (desc_a, desc_b);
799 pango_font_description_free (desc_a);
800 pango_font_description_free (desc_b);
806 font_description_style_equal (const PangoFontDescription *a,
807 const PangoFontDescription *b)
809 return (pango_font_description_get_weight (a) == pango_font_description_get_weight (b) &&
810 pango_font_description_get_style (a) == pango_font_description_get_style (b) &&
811 pango_font_description_get_stretch (a) == pango_font_description_get_stretch (b) &&
812 pango_font_description_get_variant (a) == pango_font_description_get_variant (b));
815 /* This fills the font style list with all the possible style combinations
816 for the current font family. */
818 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
821 PangoFontFace **faces;
822 PangoFontDescription *old_desc;
824 GtkTreeIter match_row;
825 PangoFontFace *match_face = NULL;
827 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list)));
830 old_desc = pango_font_face_describe (fontsel->face);
834 pango_font_family_list_faces (fontsel->family, &faces, &n_faces);
835 qsort (faces, n_faces, sizeof (PangoFontFace *), faces_sort_func);
837 gtk_list_store_clear (model);
839 for (i=0; i < n_faces; i++)
842 const gchar *str = pango_font_face_get_face_name (faces[i]);
844 gtk_list_store_append (model, &iter);
845 gtk_list_store_set (model, &iter,
846 FACE_COLUMN, faces[i],
847 FACE_NAME_COLUMN, str,
853 match_face = faces[i];
857 PangoFontDescription *tmp_desc = pango_font_face_describe (faces[i]);
859 if (font_description_style_equal (tmp_desc, old_desc))
862 match_face = faces[i];
865 pango_font_description_free (tmp_desc);
870 pango_font_description_free (old_desc);
872 fontsel->face = match_face;
875 #ifdef INCLUDE_FONT_ENTRIES
876 const gchar *str = pango_font_face_get_face_name (fontsel->face);
878 gtk_entry_set_text (GTK_ENTRY (fontsel->font_style_entry), str);
880 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_row);
886 /* This selects a style when the user selects a font. It just uses the first
887 available style at present. I was thinking of trying to maintain the
888 selected style, e.g. bold italic, when the user selects different fonts.
889 However, the interface is so easy to use now I'm not sure it's worth it.
890 Note: This will load a font. */
892 gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
898 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
900 if (gtk_tree_model_get_iter_first (model, &iter))
902 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &iter);
903 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
906 gtk_font_selection_show_available_sizes (fontsel, FALSE);
907 gtk_font_selection_select_best_size (fontsel);
911 /* This is called when a style is selected in the list. */
913 gtk_font_selection_select_style (GtkTreeSelection *selection,
916 GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
920 if (gtk_tree_selection_get_selected (selection, &model, &iter))
924 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
925 fontsel->face = face;
927 g_object_unref (face);
930 gtk_font_selection_show_available_sizes (fontsel, FALSE);
931 gtk_font_selection_select_best_size (fontsel);
935 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel,
943 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
945 /* Insert the standard font sizes */
948 gtk_list_store_clear (model);
950 for (i = 0; i < G_N_ELEMENTS (font_sizes); i++)
954 gtk_list_store_append (model, &iter);
955 gtk_list_store_set (model, &iter, SIZE_COLUMN, font_sizes[i], -1);
957 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
958 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
964 gboolean found = FALSE;
966 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
967 for (i = 0; i < G_N_ELEMENTS (font_sizes) && !found; i++)
969 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
971 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
975 gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
980 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
981 gtk_tree_selection_unselect_all (selection);
985 /* Set the entry to the new size, rounding to 1 digit,
986 * trimming of trailing 0's and a trailing period
988 g_snprintf (buffer, sizeof (buffer), "%.1f", fontsel->size / (1.0 * PANGO_SCALE));
989 if (strchr (buffer, '.'))
991 p = buffer + strlen (buffer) - 1;
999 /* Compare, to avoid moving the cursor unecessarily */
1000 if (strcmp (gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry)), buffer) != 0)
1001 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
1005 gtk_font_selection_select_best_size (GtkFontSelection *fontsel)
1007 gtk_font_selection_load_font (fontsel);
1011 gtk_font_selection_set_size (GtkFontSelection *fontsel,
1014 if (fontsel->size != new_size)
1016 fontsel->size = new_size;
1018 gtk_font_selection_show_available_sizes (fontsel, FALSE);
1019 gtk_font_selection_load_font (fontsel);
1023 /* If the user hits return in the font size entry, we change to the new font
1026 gtk_font_selection_size_activate (GtkWidget *w,
1029 GtkFontSelection *fontsel;
1033 fontsel = GTK_FONT_SELECTION (data);
1035 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1036 new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
1038 if (fontsel->size != new_size)
1039 gtk_font_selection_set_size (fontsel, new_size);
1041 list_row_activated (w);
1045 gtk_font_selection_size_focus_out (GtkWidget *w,
1046 GdkEventFocus *event,
1049 GtkFontSelection *fontsel;
1053 fontsel = GTK_FONT_SELECTION (data);
1055 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1056 new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
1058 gtk_font_selection_set_size (fontsel, new_size);
1063 /* This is called when a size is selected in the list. */
1065 gtk_font_selection_select_size (GtkTreeSelection *selection,
1068 GtkFontSelection *fontsel;
1069 GtkTreeModel *model;
1073 fontsel = GTK_FONT_SELECTION (data);
1075 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1077 gtk_tree_model_get (model, &iter, SIZE_COLUMN, &new_size, -1);
1078 gtk_font_selection_set_size (fontsel, new_size * PANGO_SCALE);
1083 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1086 gdk_font_unref (fontsel->font);
1087 fontsel->font = NULL;
1089 gtk_font_selection_update_preview (fontsel);
1092 static PangoFontDescription *
1093 gtk_font_selection_get_font_description (GtkFontSelection *fontsel)
1095 PangoFontDescription *font_desc;
1099 font_desc = pango_font_face_describe (fontsel->face);
1100 pango_font_description_set_size (font_desc, fontsel->size);
1103 font_desc = pango_font_description_from_string ("Sans 10");
1108 /* This sets the font in the preview entry to the selected font, and tries to
1109 make sure that the preview entry is a reasonable size, i.e. so that the
1110 text can be seen with a bit of space to spare. But it tries to avoid
1111 resizing the entry every time the font changes.
1112 This also used to shrink the preview if the font size was decreased, but
1113 that made it awkward if the user wanted to resize the window themself. */
1115 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1117 GtkRcStyle *rc_style;
1119 GtkRequisition old_requisition;
1120 GtkWidget *preview_entry = fontsel->preview_entry;
1123 gtk_widget_get_child_requisition (preview_entry, &old_requisition);
1125 rc_style = gtk_rc_style_new ();
1126 rc_style->font_desc = gtk_font_selection_get_font_description (fontsel);
1128 gtk_widget_modify_style (preview_entry, rc_style);
1129 gtk_rc_style_unref (rc_style);
1131 gtk_widget_size_request (preview_entry, NULL);
1133 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1134 new_height = CLAMP (preview_entry->requisition.height, INITIAL_PREVIEW_HEIGHT, MAX_PREVIEW_HEIGHT);
1136 if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
1137 gtk_widget_set_size_request (preview_entry, -1, new_height);
1139 /* This sets the preview text, if it hasn't been set already. */
1140 text = gtk_entry_get_text (GTK_ENTRY (preview_entry));
1141 if (strlen (text) == 0)
1142 gtk_entry_set_text (GTK_ENTRY (preview_entry), _(PREVIEW_TEXT));
1143 gtk_editable_set_position (GTK_EDITABLE (preview_entry), 0);
1147 gtk_font_selection_get_font_internal (GtkFontSelection *fontsel)
1151 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1152 fontsel->font = gdk_font_from_description_for_display (gtk_widget_get_display (GTK_WIDGET (fontsel)), font_desc);
1153 pango_font_description_free (font_desc);
1156 return fontsel->font;
1160 /*****************************************************************************
1161 * These functions are the main public interface for getting/setting the font.
1162 *****************************************************************************/
1165 gtk_font_selection_get_font (GtkFontSelection *fontsel)
1167 return gtk_font_selection_get_font_internal (fontsel);
1171 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
1175 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1176 result = pango_font_description_to_string (font_desc);
1177 pango_font_description_free (font_desc);
1183 /* This sets the current font, selecting the appropriate list rows.
1184 First we check the fontname is valid and try to find the font family
1185 - i.e. the name in the main list. If we can't find that, then just return.
1186 Next we try to set each of the properties according to the fontname.
1187 Finally we select the font family & style in the lists. */
1189 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
1190 const gchar *fontname)
1192 PangoFontFamily *new_family = NULL;
1193 PangoFontFace *new_face = NULL;
1194 PangoFontFace *fallback_face = NULL;
1195 PangoFontDescription *new_desc;
1196 GtkTreeModel *model;
1198 GtkTreeIter match_iter;
1200 const gchar *new_family_name;
1202 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
1204 new_desc = pango_font_description_from_string (fontname);
1205 new_family_name = pango_font_description_get_family (new_desc);
1207 if (!new_family_name)
1210 /* Check to make sure that this is in the list of allowed fonts
1212 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list));
1213 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1215 valid = gtk_tree_model_iter_next (model, &iter))
1217 PangoFontFamily *family;
1219 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
1221 if (g_ascii_strcasecmp (pango_font_family_get_name (family),
1222 new_family_name) == 0)
1223 new_family = family;
1225 g_object_unref (family);
1234 fontsel->family = new_family;
1235 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &iter);
1236 gtk_font_selection_show_available_styles (fontsel);
1238 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1239 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1241 valid = gtk_tree_model_iter_next (model, &iter))
1243 PangoFontFace *face;
1244 PangoFontDescription *tmp_desc;
1246 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
1247 tmp_desc = pango_font_face_describe (face);
1249 if (font_description_style_equal (tmp_desc, new_desc))
1254 fallback_face = face;
1258 pango_font_description_free (tmp_desc);
1259 g_object_unref (face);
1269 new_face = fallback_face;
1271 fontsel->face = new_face;
1272 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_iter);
1274 gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
1276 g_object_freeze_notify (G_OBJECT (fontsel));
1277 g_object_notify (G_OBJECT (fontsel), "font_name");
1278 g_object_notify (G_OBJECT (fontsel), "font");
1279 g_object_thaw_notify (G_OBJECT (fontsel));
1281 pango_font_description_free (new_desc);
1287 /* This returns the text in the preview entry. You should copy the returned
1288 text if you need it. */
1289 G_CONST_RETURN gchar*
1290 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
1292 return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
1296 /* This sets the text in the preview entry. */
1298 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
1301 gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
1304 /*****************************************************************************
1305 * GtkFontSelectionDialog
1306 *****************************************************************************/
1309 gtk_font_selection_dialog_get_type (void)
1311 static GType font_selection_dialog_type = 0;
1313 if (!font_selection_dialog_type)
1315 static const GTypeInfo fontsel_diag_info =
1317 sizeof (GtkFontSelectionDialogClass),
1318 NULL, /* base_init */
1319 NULL, /* base_finalize */
1320 (GClassInitFunc) gtk_font_selection_dialog_class_init,
1321 NULL, /* class_finalize */
1322 NULL, /* class_data */
1323 sizeof (GtkFontSelectionDialog),
1324 0, /* n_preallocs */
1325 (GInstanceInitFunc) gtk_font_selection_dialog_init,
1328 font_selection_dialog_type =
1329 g_type_register_static (GTK_TYPE_DIALOG, I_("GtkFontSelectionDialog"),
1330 &fontsel_diag_info, 0);
1333 return font_selection_dialog_type;
1337 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1339 font_selection_dialog_parent_class = g_type_class_peek_parent (klass);
1343 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1347 gtk_widget_push_composite_child ();
1349 dialog = GTK_DIALOG (fontseldiag);
1351 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
1352 gtk_window_set_resizable (GTK_WINDOW (fontseldiag), TRUE);
1354 fontseldiag->main_vbox = dialog->vbox;
1356 fontseldiag->fontsel = gtk_font_selection_new ();
1357 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 4);
1358 gtk_widget_show (fontseldiag->fontsel);
1359 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
1360 fontseldiag->fontsel, TRUE, TRUE, 0);
1362 /* Create the action area */
1363 fontseldiag->action_area = dialog->action_area;
1365 fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1367 GTK_RESPONSE_CANCEL);
1369 fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1371 GTK_RESPONSE_APPLY);
1372 gtk_widget_hide (fontseldiag->apply_button);
1374 fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1377 gtk_widget_grab_default (fontseldiag->ok_button);
1379 gtk_dialog_set_alternative_button_order (GTK_DIALOG (fontseldiag),
1382 GTK_RESPONSE_CANCEL,
1386 gtk_window_set_title (GTK_WINDOW (fontseldiag),
1387 _("Font Selection"));
1389 gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
1391 gtk_widget_pop_composite_child ();
1395 gtk_font_selection_dialog_new (const gchar *title)
1397 GtkFontSelectionDialog *fontseldiag;
1399 fontseldiag = g_object_new (GTK_TYPE_FONT_SELECTION_DIALOG, NULL);
1402 gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1404 return GTK_WIDGET (fontseldiag);
1408 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1410 return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1414 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1416 return gtk_font_selection_get_font (GTK_FONT_SELECTION (fsd->fontsel));
1420 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1421 const gchar *fontname)
1423 return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1426 G_CONST_RETURN gchar*
1427 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1429 return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1433 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1436 gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);
1439 #define __GTK_FONTSEL_C__
1440 #include "gtkaliasdef.c"