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, "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 const gchar *family_name;
686 fontsel = GTK_FONT_SELECTION (data);
688 if (gtk_tree_selection_get_selected (selection, &model, &iter))
690 PangoFontFamily *family;
692 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
693 if (fontsel->family != family)
695 fontsel->family = family;
697 family_name = pango_font_family_get_name (fontsel->family);
699 #ifdef INCLUDE_FONT_ENTRIES
700 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
703 gtk_font_selection_show_available_styles (fontsel);
704 gtk_font_selection_select_best_style (fontsel, TRUE);
707 g_object_unref (family);
712 cmp_families (const void *a, const void *b)
714 const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
715 const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
717 return g_utf8_collate (a_name, b_name);
721 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
724 PangoFontFamily **families;
725 PangoFontFamily *match_family = NULL;
727 GtkTreeIter match_row;
729 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list)));
731 pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
732 &families, &n_families);
733 qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families);
735 gtk_list_store_clear (model);
737 for (i=0; i<n_families; i++)
739 const gchar *name = pango_font_family_get_name (families[i]);
742 gtk_list_store_append (model, &iter);
743 gtk_list_store_set (model, &iter,
744 FAMILY_COLUMN, families[i],
745 FAMILY_NAME_COLUMN, name,
748 if (i == 0 || !g_ascii_strcasecmp (name, "sans"))
750 match_family = families[i];
755 fontsel->family = match_family;
758 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &match_row);
759 #ifdef INCLUDE_FONT_ENTRIES
760 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry),
761 pango_font_family_get_name (match_family));
762 #endif /* INCLUDE_FONT_ENTRIES */
769 compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
771 int val = strcmp (pango_font_description_get_family (a), pango_font_description_get_family (b));
775 if (pango_font_description_get_weight (a) != pango_font_description_get_weight (b))
776 return pango_font_description_get_weight (a) - pango_font_description_get_weight (b);
778 if (pango_font_description_get_style (a) != pango_font_description_get_style (b))
779 return pango_font_description_get_style (a) - pango_font_description_get_style (b);
781 if (pango_font_description_get_stretch (a) != pango_font_description_get_stretch (b))
782 return pango_font_description_get_stretch (a) - pango_font_description_get_stretch (b);
784 if (pango_font_description_get_variant (a) != pango_font_description_get_variant (b))
785 return pango_font_description_get_variant (a) - pango_font_description_get_variant (b);
791 faces_sort_func (const void *a, const void *b)
793 PangoFontDescription *desc_a = pango_font_face_describe (*(PangoFontFace **)a);
794 PangoFontDescription *desc_b = pango_font_face_describe (*(PangoFontFace **)b);
796 int ord = compare_font_descriptions (desc_a, desc_b);
798 pango_font_description_free (desc_a);
799 pango_font_description_free (desc_b);
805 font_description_style_equal (const PangoFontDescription *a,
806 const PangoFontDescription *b)
808 return (pango_font_description_get_weight (a) == pango_font_description_get_weight (b) &&
809 pango_font_description_get_style (a) == pango_font_description_get_style (b) &&
810 pango_font_description_get_stretch (a) == pango_font_description_get_stretch (b) &&
811 pango_font_description_get_variant (a) == pango_font_description_get_variant (b));
814 /* This fills the font style list with all the possible style combinations
815 for the current font family. */
817 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
820 PangoFontFace **faces;
821 PangoFontDescription *old_desc;
823 GtkTreeIter match_row;
824 PangoFontFace *match_face = NULL;
826 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list)));
829 old_desc = pango_font_face_describe (fontsel->face);
833 pango_font_family_list_faces (fontsel->family, &faces, &n_faces);
834 qsort (faces, n_faces, sizeof (PangoFontFace *), faces_sort_func);
836 gtk_list_store_clear (model);
838 for (i=0; i < n_faces; i++)
841 const gchar *str = pango_font_face_get_face_name (faces[i]);
843 gtk_list_store_append (model, &iter);
844 gtk_list_store_set (model, &iter,
845 FACE_COLUMN, faces[i],
846 FACE_NAME_COLUMN, str,
852 match_face = faces[i];
856 PangoFontDescription *tmp_desc = pango_font_face_describe (faces[i]);
858 if (font_description_style_equal (tmp_desc, old_desc))
861 match_face = faces[i];
864 pango_font_description_free (tmp_desc);
869 pango_font_description_free (old_desc);
871 fontsel->face = match_face;
874 #ifdef INCLUDE_FONT_ENTRIES
875 const gchar *str = pango_font_face_get_face_name (fontsel->face);
877 gtk_entry_set_text (GTK_ENTRY (fontsel->font_style_entry), str);
879 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_row);
885 /* This selects a style when the user selects a font. It just uses the first
886 available style at present. I was thinking of trying to maintain the
887 selected style, e.g. bold italic, when the user selects different fonts.
888 However, the interface is so easy to use now I'm not sure it's worth it.
889 Note: This will load a font. */
891 gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
897 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
899 if (gtk_tree_model_get_iter_first (model, &iter))
901 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &iter);
902 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
905 gtk_font_selection_show_available_sizes (fontsel, FALSE);
906 gtk_font_selection_select_best_size (fontsel);
910 /* This is called when a style is selected in the list. */
912 gtk_font_selection_select_style (GtkTreeSelection *selection,
915 GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
919 if (gtk_tree_selection_get_selected (selection, &model, &iter))
923 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
924 fontsel->face = face;
926 g_object_unref (face);
929 gtk_font_selection_show_available_sizes (fontsel, FALSE);
930 gtk_font_selection_select_best_size (fontsel);
934 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel,
939 GtkTreeSelection *selection;
943 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
944 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
946 /* Insert the standard font sizes */
949 gtk_list_store_clear (model);
951 for (i = 0; i < G_N_ELEMENTS (font_sizes); i++)
955 gtk_list_store_append (model, &iter);
956 gtk_list_store_set (model, &iter, SIZE_COLUMN, font_sizes[i], -1);
958 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
959 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
965 gboolean found = FALSE;
967 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
968 for (i = 0; i < G_N_ELEMENTS (font_sizes) && !found; i++)
970 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
972 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
976 gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
981 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
982 gtk_tree_selection_unselect_all (selection);
986 /* Set the entry to the new size, rounding to 1 digit,
987 * trimming of trailing 0's and a trailing period
989 g_snprintf (buffer, sizeof (buffer), "%.1f", fontsel->size / (1.0 * PANGO_SCALE));
990 if (strchr (buffer, '.'))
992 p = buffer + strlen (buffer) - 1;
1000 /* Compare, to avoid moving the cursor unecessarily */
1001 if (strcmp (gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry)), buffer) != 0)
1002 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
1006 gtk_font_selection_select_best_size (GtkFontSelection *fontsel)
1008 gtk_font_selection_load_font (fontsel);
1012 gtk_font_selection_set_size (GtkFontSelection *fontsel,
1015 if (fontsel->size != new_size)
1017 fontsel->size = new_size;
1019 gtk_font_selection_show_available_sizes (fontsel, FALSE);
1020 gtk_font_selection_load_font (fontsel);
1024 /* If the user hits return in the font size entry, we change to the new font
1027 gtk_font_selection_size_activate (GtkWidget *w,
1030 GtkFontSelection *fontsel;
1034 fontsel = GTK_FONT_SELECTION (data);
1036 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1037 new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
1039 if (fontsel->size != new_size)
1040 gtk_font_selection_set_size (fontsel, new_size);
1042 list_row_activated (w);
1046 gtk_font_selection_size_focus_out (GtkWidget *w,
1047 GdkEventFocus *event,
1050 GtkFontSelection *fontsel;
1054 fontsel = GTK_FONT_SELECTION (data);
1056 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1057 new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
1059 gtk_font_selection_set_size (fontsel, new_size);
1064 /* This is called when a size is selected in the list. */
1066 gtk_font_selection_select_size (GtkTreeSelection *selection,
1069 GtkFontSelection *fontsel;
1070 GtkTreeModel *model;
1074 fontsel = GTK_FONT_SELECTION (data);
1076 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1078 gtk_tree_model_get (model, &iter, SIZE_COLUMN, &new_size, -1);
1079 gtk_font_selection_set_size (fontsel, new_size * PANGO_SCALE);
1084 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1087 gdk_font_unref (fontsel->font);
1088 fontsel->font = NULL;
1090 gtk_font_selection_update_preview (fontsel);
1093 static PangoFontDescription *
1094 gtk_font_selection_get_font_description (GtkFontSelection *fontsel)
1096 PangoFontDescription *font_desc;
1100 font_desc = pango_font_face_describe (fontsel->face);
1101 pango_font_description_set_size (font_desc, fontsel->size);
1104 font_desc = pango_font_description_from_string ("Sans 10");
1109 /* This sets the font in the preview entry to the selected font, and tries to
1110 make sure that the preview entry is a reasonable size, i.e. so that the
1111 text can be seen with a bit of space to spare. But it tries to avoid
1112 resizing the entry every time the font changes.
1113 This also used to shrink the preview if the font size was decreased, but
1114 that made it awkward if the user wanted to resize the window themself. */
1116 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1118 GtkRcStyle *rc_style;
1120 GtkRequisition old_requisition;
1121 GtkWidget *preview_entry = fontsel->preview_entry;
1124 gtk_widget_get_child_requisition (preview_entry, &old_requisition);
1126 rc_style = gtk_rc_style_new ();
1127 rc_style->font_desc = gtk_font_selection_get_font_description (fontsel);
1129 gtk_widget_modify_style (preview_entry, rc_style);
1130 gtk_rc_style_unref (rc_style);
1132 gtk_widget_size_request (preview_entry, NULL);
1134 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1135 new_height = CLAMP (preview_entry->requisition.height, INITIAL_PREVIEW_HEIGHT, MAX_PREVIEW_HEIGHT);
1137 if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
1138 gtk_widget_set_size_request (preview_entry, -1, new_height);
1140 /* This sets the preview text, if it hasn't been set already. */
1141 text = gtk_entry_get_text (GTK_ENTRY (preview_entry));
1142 if (strlen (text) == 0)
1143 gtk_entry_set_text (GTK_ENTRY (preview_entry), _(PREVIEW_TEXT));
1144 gtk_editable_set_position (GTK_EDITABLE (preview_entry), 0);
1148 gtk_font_selection_get_font_internal (GtkFontSelection *fontsel)
1152 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1153 fontsel->font = gdk_font_from_description_for_display (gtk_widget_get_display (GTK_WIDGET (fontsel)), font_desc);
1154 pango_font_description_free (font_desc);
1157 return fontsel->font;
1161 /*****************************************************************************
1162 * These functions are the main public interface for getting/setting the font.
1163 *****************************************************************************/
1166 gtk_font_selection_get_font (GtkFontSelection *fontsel)
1168 return gtk_font_selection_get_font_internal (fontsel);
1172 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
1176 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1177 result = pango_font_description_to_string (font_desc);
1178 pango_font_description_free (font_desc);
1184 /* This sets the current font, selecting the appropriate list rows.
1185 First we check the fontname is valid and try to find the font family
1186 - i.e. the name in the main list. If we can't find that, then just return.
1187 Next we try to set each of the properties according to the fontname.
1188 Finally we select the font family & style in the lists. */
1190 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
1191 const gchar *fontname)
1193 PangoFontFamily *new_family = NULL;
1194 PangoFontFace *new_face = NULL;
1195 PangoFontFace *fallback_face = NULL;
1196 PangoFontDescription *new_desc;
1197 GtkTreeModel *model;
1199 GtkTreeIter match_iter;
1202 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
1204 new_desc = pango_font_description_from_string (fontname);
1206 /* Check to make sure that this is in the list of allowed fonts */
1208 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list));
1209 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1211 valid = gtk_tree_model_iter_next (model, &iter))
1213 PangoFontFamily *family;
1215 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
1217 if (g_ascii_strcasecmp (pango_font_family_get_name (family),
1218 pango_font_description_get_family (new_desc)) == 0)
1219 new_family = family;
1221 g_object_unref (family);
1230 fontsel->family = new_family;
1231 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &iter);
1232 gtk_font_selection_show_available_styles (fontsel);
1234 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1235 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1237 valid = gtk_tree_model_iter_next (model, &iter))
1239 PangoFontFace *face;
1240 PangoFontDescription *tmp_desc;
1242 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
1243 tmp_desc = pango_font_face_describe (face);
1245 if (font_description_style_equal (tmp_desc, new_desc))
1250 fallback_face = face;
1254 pango_font_description_free (tmp_desc);
1255 g_object_unref (face);
1265 new_face = fallback_face;
1267 fontsel->face = new_face;
1268 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_iter);
1270 gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
1272 g_object_freeze_notify (G_OBJECT (fontsel));
1273 g_object_notify (G_OBJECT (fontsel), "font_name");
1274 g_object_notify (G_OBJECT (fontsel), "font");
1275 g_object_thaw_notify (G_OBJECT (fontsel));
1277 pango_font_description_free (new_desc);
1283 /* This returns the text in the preview entry. You should copy the returned
1284 text if you need it. */
1285 G_CONST_RETURN gchar*
1286 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
1288 return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
1292 /* This sets the text in the preview entry. */
1294 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
1297 gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
1300 /*****************************************************************************
1301 * GtkFontSelectionDialog
1302 *****************************************************************************/
1305 gtk_font_selection_dialog_get_type (void)
1307 static GType font_selection_dialog_type = 0;
1309 if (!font_selection_dialog_type)
1311 static const GTypeInfo fontsel_diag_info =
1313 sizeof (GtkFontSelectionDialogClass),
1314 NULL, /* base_init */
1315 NULL, /* base_finalize */
1316 (GClassInitFunc) gtk_font_selection_dialog_class_init,
1317 NULL, /* class_finalize */
1318 NULL, /* class_data */
1319 sizeof (GtkFontSelectionDialog),
1320 0, /* n_preallocs */
1321 (GInstanceInitFunc) gtk_font_selection_dialog_init,
1324 font_selection_dialog_type =
1325 g_type_register_static (GTK_TYPE_DIALOG, "GtkFontSelectionDialog",
1326 &fontsel_diag_info, 0);
1329 return font_selection_dialog_type;
1333 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1335 font_selection_dialog_parent_class = g_type_class_peek_parent (klass);
1339 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1343 gtk_widget_push_composite_child ();
1345 dialog = GTK_DIALOG (fontseldiag);
1347 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
1348 gtk_window_set_resizable (GTK_WINDOW (fontseldiag), TRUE);
1350 fontseldiag->main_vbox = dialog->vbox;
1352 fontseldiag->fontsel = gtk_font_selection_new ();
1353 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 4);
1354 gtk_widget_show (fontseldiag->fontsel);
1355 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
1356 fontseldiag->fontsel, TRUE, TRUE, 0);
1358 /* Create the action area */
1359 fontseldiag->action_area = dialog->action_area;
1361 fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1363 GTK_RESPONSE_CANCEL);
1365 fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1367 GTK_RESPONSE_APPLY);
1368 gtk_widget_hide (fontseldiag->apply_button);
1370 fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1373 gtk_widget_grab_default (fontseldiag->ok_button);
1375 gtk_dialog_set_alternative_button_order (GTK_DIALOG (fontseldiag),
1378 GTK_RESPONSE_CANCEL,
1382 gtk_window_set_title (GTK_WINDOW (fontseldiag),
1383 _("Font Selection"));
1385 gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
1387 gtk_widget_pop_composite_child ();
1391 gtk_font_selection_dialog_new (const gchar *title)
1393 GtkFontSelectionDialog *fontseldiag;
1395 fontseldiag = g_object_new (GTK_TYPE_FONT_SELECTION_DIALOG, NULL);
1398 gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1400 return GTK_WIDGET (fontseldiag);
1404 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1406 return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1410 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1412 return gtk_font_selection_get_font (GTK_FONT_SELECTION (fsd->fontsel));
1416 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1417 const gchar *fontname)
1419 return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1422 G_CONST_RETURN gchar*
1423 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1425 return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1429 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1432 gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);
1435 #define __GTK_FONTSEL_C__
1436 #include "gtkaliasdef.c"