/* GnomeFontSelector widget, by Elliot Lee. Derived from app/text_tool.c in: */ /* The GIMP -- an image manipulation program * Copyright (C) 1995, 1998 Spencer Kimball and Peter Mattis * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include "gnome-font-selector.h" #include "libgnome/libgnomeP.h" #include "gnome-app.h" #include "gnome-app-helper.h" #include "gdk/gdkkeysyms.h" #define FONT_LIST_WIDTH 125 #define FONT_LIST_HEIGHT 200 #define PIXELS 0 #define POINTS 1 #define FOUNDRY 0 #define FAMILY 1 #define WEIGHT 2 #define SLANT 3 #define SET_WIDTH 4 #define SPACING 10 #define SUPERSAMPLE 3 struct _FontInfo { gchar *family; /* The font family this info struct describes. */ gint *foundries; /* An array of valid foundries. */ gint *weights; /* An array of valid weights. */ gint *slants; /* An array of valid slants. */ gint *set_widths; /* An array of valid set widths. */ gint *spacings; /* An array of valid spacings */ gint **combos; /* An array of valid combinations of the above 5 items */ gint ncombos; /* The number of elements in the "combos" array */ GSList *fontnames; /* An list of valid fontnames. * This is used to make sure a family/foundry/weight/slant/set_width * combination is valid. */ }; static void gnome_font_selector_class_init(GnomeFontSelectorClass *klass); static void gnome_font_selector_init(GtkWidget *widget); static void text_resize_text_widget (GnomeFontSelector *); static void text_ok_callback (GtkWidget *, gpointer); static void text_cancel_callback (GtkWidget *, gpointer); static gint text_delete_callback (GtkWidget *, GdkEvent *, gpointer); static void text_pixels_callback (GtkWidget *, gpointer); #if 0 /* Commented out until used. */ static void text_points_callback (GtkWidget *, gpointer); #endif static void text_foundry_callback (GtkWidget *, gpointer); static void text_weight_callback (GtkWidget *, gpointer); static void text_slant_callback (GtkWidget *, gpointer); static void text_set_width_callback (GtkWidget *, gpointer); static void text_spacing_callback (GtkWidget *, gpointer); static gint text_size_key_function (GtkWidget *, GdkEventKey *, gpointer); static void text_font_item_update (GtkWidget *, gpointer); static void text_validate_combo (GnomeFontSelector *, gint); static void text_get_fonts (GnomeFontSelectorClass *klass); static void text_insert_font (FontInfo **, gint *, const gchar *); static GSList* text_insert_field (GSList *, const gchar *, gint); static gchar* text_get_field (const gchar *, gint); static gint text_field_to_index (gchar **, gint, const gchar *); static gint text_is_xlfd_font_name (const gchar *); static gchar * text_get_xlfd (gdouble, gint, const gchar *, const gchar *, const gchar *, const gchar *, const gchar *, const gchar *); static gint text_load_font (GnomeFontSelector *); typedef GtkSignalFunc MenuItemCallback; typedef struct { gchar *label; gint foo, bar; gpointer cb, cbdata, blah, baz; } MenuItem; static GnomeUIInfo size_metric_items[] = { { GNOME_APP_UI_ITEM, "Pixels", "Use pixels as the unit of measurement", text_pixels_callback, NULL, NULL, GNOME_APP_PIXMAP_NONE, NULL, 0, 0, NULL}, { GNOME_APP_UI_ITEM, "Points", "Use points as the unit of measurement", text_pixels_callback, NULL, NULL, GNOME_APP_PIXMAP_NONE, NULL, 0, 0, NULL}, { GNOME_APP_UI_ENDOFINFO, NULL, NULL, NULL } }; guint gnome_font_selector_get_type(void) { static guint gnomefontsel_type = 0; if(!gnomefontsel_type) { GtkTypeInfo gnomefontsel_info = { "GnomeFontSelector", sizeof(GnomeFontSelector), sizeof(GnomeFontSelectorClass), (GtkClassInitFunc) gnome_font_selector_class_init, (GtkObjectInitFunc) gnome_font_selector_init, (GtkArgSetFunc) NULL, (GtkArgGetFunc) NULL, }; gnomefontsel_type = gtk_type_unique(gtk_dialog_get_type(), &gnomefontsel_info); } return gnomefontsel_type; } static void gnome_font_selector_class_init(GnomeFontSelectorClass *klass) { text_get_fonts(klass); } static void gnome_font_selector_init(GtkWidget *widget) { GtkWidget *top_hbox; GtkWidget *right_vbox; GtkWidget *text_hbox; GtkWidget *list_box; GtkWidget *list_item; GtkWidget *size_opt_menu; GtkWidget *border_label; GtkWidget *menu_table; GtkWidget *menu_label; GtkWidget **menu_items[5]; GtkWidget *alignment; int nmenu_items[5]; char *menu_strs[5]; char **menu_item_strs[5]; int *font_infos[5]; MenuItemCallback menu_callbacks[5]; int i, j; FontInfo **font_info; int nfonts; GnomeFontSelectorClass *klass; GnomeFontSelector *text_tool; text_tool = GNOME_FONT_SELECTOR(widget); klass = GNOME_FONT_SELECTOR_CLASS(GTK_OBJECT(widget)->klass); font_info = klass->font_info; nfonts = klass->nfonts; /* Create the shell and vertical & horizontal boxes */ gtk_window_set_title (GTK_WINDOW (text_tool), "Font Selector"); gtk_window_set_policy (GTK_WINDOW (text_tool), FALSE, TRUE, TRUE); gtk_window_set_position (GTK_WINDOW (text_tool), GTK_WIN_POS_MOUSE); /* handle the wm close signal */ gtk_signal_connect (GTK_OBJECT (text_tool), "delete_event", GTK_SIGNAL_FUNC (text_delete_callback), text_tool); text_tool->main_vbox = gtk_vbox_new (FALSE, 2); gtk_container_set_border_width (GTK_CONTAINER (text_tool->main_vbox), 2); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (text_tool)->vbox), text_tool->main_vbox, TRUE, TRUE, 0); top_hbox = gtk_hbox_new (FALSE, 1); gtk_box_pack_start (GTK_BOX (text_tool->main_vbox), top_hbox, TRUE, TRUE, 0); /* Create the font listbox */ list_box = gtk_scrolled_window_new (NULL, NULL); gtk_widget_set_usize (list_box, FONT_LIST_WIDTH, FONT_LIST_HEIGHT); gtk_box_pack_start (GTK_BOX (top_hbox), list_box, TRUE, TRUE, 0); text_tool->font_list = gtk_list_new (); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (list_box), text_tool->font_list); gtk_list_set_selection_mode (GTK_LIST (text_tool->font_list), GTK_SELECTION_BROWSE); for (i = 0; i < nfonts; i++) { list_item = gtk_list_item_new_with_label (font_info[i]->family); gtk_object_set_data(GTK_OBJECT(list_item), "GnomeFontSelector", (gpointer)text_tool); gtk_container_add (GTK_CONTAINER (text_tool->font_list), list_item); gtk_signal_connect (GTK_OBJECT (list_item), "select", (GtkSignalFunc) text_font_item_update, (gpointer) ((long) i)); gtk_widget_show (list_item); } gtk_widget_show (text_tool->font_list); /* Create the box to hold options */ right_vbox = gtk_vbox_new (FALSE, 2); gtk_box_pack_start (GTK_BOX (top_hbox), right_vbox, TRUE, TRUE, 2); /* Create the text hbox, size text, and fonts size metric option menu */ text_hbox = gtk_hbox_new (FALSE, 2); gtk_box_pack_start (GTK_BOX (right_vbox), text_hbox, FALSE, FALSE, 0); text_tool->size_text = gtk_entry_new (); gtk_widget_set_usize (text_tool->size_text, 75, 0); gtk_entry_set_text (GTK_ENTRY (text_tool->size_text), "50"); gtk_signal_connect (GTK_OBJECT (text_tool->size_text), "key_press_event", (GtkSignalFunc) text_size_key_function, text_tool); gtk_box_pack_start (GTK_BOX (text_hbox), text_tool->size_text, TRUE, TRUE, 0); /* Create the size menu */ text_tool->size_menu = gtk_menu_new(); for(i = 0; size_metric_items[i].type != GNOME_APP_UI_ENDOFINFO; i++) { size_metric_items[i].widget = gtk_menu_item_new_with_label(size_metric_items[i].label); gtk_signal_connect(GTK_OBJECT(size_metric_items[i].widget), "activate", size_metric_items[i].moreinfo, text_tool); gtk_widget_show(size_metric_items[i].widget); gtk_menu_append(GTK_MENU(text_tool->size_menu), size_metric_items[i].widget); } size_opt_menu = gtk_option_menu_new (); gtk_box_pack_start (GTK_BOX (text_hbox), size_opt_menu, FALSE, FALSE, 0); /* create the text entry widget */ text_tool->text_frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (text_tool->text_frame), GTK_SHADOW_NONE); gtk_box_pack_start (GTK_BOX (text_tool->main_vbox), text_tool->text_frame, FALSE, FALSE, 2); text_tool->the_text = gtk_entry_new (); gtk_entry_set_text(GTK_ENTRY(text_tool->the_text), "AaBbCcDdEeFfGgHh"); gtk_entry_set_position(GTK_ENTRY(text_tool->the_text), 0); gtk_container_add (GTK_CONTAINER (text_tool->text_frame), text_tool->the_text); /* Allocate the arrays for the foundry, weight, slant, set_width and spacing menu items */ text_tool->foundry_items = (GtkWidget **) g_malloc (sizeof (GtkWidget *) * klass->nfoundries); text_tool->weight_items = (GtkWidget **) g_malloc (sizeof (GtkWidget *) * klass->nweights); text_tool->slant_items = (GtkWidget **) g_malloc (sizeof (GtkWidget *) * klass->nslants); text_tool->set_width_items = (GtkWidget **) g_malloc (sizeof (GtkWidget *) * klass->nset_widths); text_tool->spacing_items = (GtkWidget **) g_malloc (sizeof (GtkWidget *) * klass->nspacings); menu_items[0] = text_tool->foundry_items; menu_items[1] = text_tool->weight_items; menu_items[2] = text_tool->slant_items; menu_items[3] = text_tool->set_width_items; menu_items[4] = text_tool->spacing_items; nmenu_items[0] = klass->nfoundries; nmenu_items[1] = klass->nweights; nmenu_items[2] = klass->nslants; nmenu_items[3] = klass->nset_widths; nmenu_items[4] = klass->nspacings; menu_strs[0] = "Foundry"; menu_strs[1] = "Weight"; menu_strs[2] = "Slant"; menu_strs[3] = "Set width"; menu_strs[4] = "Spacing"; menu_item_strs[0] = klass->foundry_array; menu_item_strs[1] = klass->weight_array; menu_item_strs[2] = klass->slant_array; menu_item_strs[3] = klass->set_width_array; menu_item_strs[4] = klass->spacing_array; menu_callbacks[0] = GTK_SIGNAL_FUNC(text_foundry_callback); menu_callbacks[1] = GTK_SIGNAL_FUNC(text_weight_callback); menu_callbacks[2] = GTK_SIGNAL_FUNC(text_slant_callback); menu_callbacks[3] = GTK_SIGNAL_FUNC(text_set_width_callback); menu_callbacks[4] = GTK_SIGNAL_FUNC(text_spacing_callback); font_infos[0] = font_info[0]->foundries; font_infos[1] = font_info[0]->weights; font_infos[2] = font_info[0]->slants; font_infos[3] = font_info[0]->set_widths; font_infos[4] = font_info[0]->spacings; menu_table = gtk_table_new (6, 2, FALSE); gtk_box_pack_start (GTK_BOX (right_vbox), menu_table, TRUE, TRUE, 0); /* Create the other menus */ for (i = 0; i < 5; i++) { menu_label = gtk_label_new (menu_strs[i]); gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (menu_table), menu_label, 0, 1, i, i + 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 0, 1); alignment = gtk_alignment_new (0.0, 0.0, 0.0, 0.0); gtk_table_attach (GTK_TABLE (menu_table), alignment, 1, 2, i, i + 1, GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 1, 1); text_tool->menus[i] = gtk_menu_new (); for (j = 0; j < nmenu_items[i]; j++) { menu_items[i][j] = gtk_menu_item_new_with_label (menu_item_strs[i][j]); gtk_widget_set_sensitive (menu_items[i][j], font_infos[i][j]); gtk_container_add (GTK_CONTAINER (text_tool->menus[i]), menu_items[i][j]); gtk_object_set_data(GTK_OBJECT(menu_items[i][j]), "GnomeFontSelector", text_tool); gtk_signal_connect (GTK_OBJECT (menu_items[i][j]), "activate", (GtkSignalFunc) menu_callbacks[i], (gpointer) ((long) j)); gtk_widget_show (menu_items[i][j]); } text_tool->option_menus[i] = gtk_option_menu_new (); gtk_container_add (GTK_CONTAINER (alignment), text_tool->option_menus[i]); gtk_widget_show (menu_label); gtk_widget_show (text_tool->option_menus[i]); gtk_widget_show (alignment); gtk_option_menu_set_menu (GTK_OPTION_MENU (text_tool->option_menus[i]), text_tool->menus[i]); } /* Create the border text hbox, border text, and label */ border_label = gtk_label_new ("Border"); gtk_misc_set_alignment (GTK_MISC (border_label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (menu_table), border_label, 0, 1, i, i + 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 0, 1); alignment = gtk_alignment_new (0.0, 0.0, 0.0, 0.0); gtk_table_attach (GTK_TABLE (menu_table), alignment, 1, 2, i, i + 1, GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 1, 1); text_tool->border_text = gtk_entry_new (); gtk_widget_set_usize (text_tool->border_text, 75, 25); gtk_entry_set_text (GTK_ENTRY (text_tool->border_text), "0"); gtk_container_add (GTK_CONTAINER (alignment), text_tool->border_text); gtk_widget_show (alignment); /* Create the action area */ text_tool->ok_button = gtk_button_new_with_label("OK"); gtk_signal_connect(GTK_OBJECT(text_tool->ok_button), "clicked", GTK_SIGNAL_FUNC(text_ok_callback), text_tool); gtk_widget_show(text_tool->ok_button); gtk_box_pack_start (GTK_BOX (GTK_DIALOG(text_tool)->action_area), text_tool->ok_button, TRUE, TRUE, 0); text_tool->cancel_button = gtk_button_new_with_label("Cancel"); gtk_signal_connect(GTK_OBJECT(text_tool->cancel_button), "clicked", GTK_SIGNAL_FUNC(text_cancel_callback), text_tool); gtk_widget_show(text_tool->cancel_button); gtk_box_pack_start (GTK_BOX(GTK_DIALOG(text_tool)->action_area), text_tool->cancel_button, TRUE, TRUE, 0); /* Show the widgets */ gtk_widget_show (menu_table); gtk_widget_show (text_tool->size_text); gtk_widget_show (border_label); gtk_widget_show (text_tool->border_text); gtk_widget_show (size_opt_menu); gtk_widget_show (text_hbox); gtk_widget_show (list_box); gtk_widget_show (right_vbox); gtk_widget_show (top_hbox); gtk_widget_show (text_tool->the_text); gtk_widget_show (text_tool->text_frame); gtk_widget_show (text_tool->main_vbox); /* Post initialization */ gtk_option_menu_set_menu (GTK_OPTION_MENU (size_opt_menu), text_tool->size_menu); if (nfonts) text_load_font (text_tool); } /** * gnome_font_selector_new: * * Returns: a newly created font selector widget */ GtkWidget * gnome_font_selector_new(void) { return gtk_type_new(gnome_font_selector_get_type()); } static void text_resize_text_widget (GnomeFontSelector *text_tool) { GtkStyle *style; style = gtk_style_new (); gdk_font_unref (style->font); style->font = text_tool->font; gdk_font_ref (style->font); gtk_widget_set_style (text_tool->the_text, style); gtk_style_unref(style); } static void text_ok_callback (GtkWidget *w, gpointer client_data) { GnomeFontSelector * text_tool; text_tool = GNOME_FONT_SELECTOR(client_data); if (GTK_WIDGET_VISIBLE (text_tool)) gtk_widget_hide (GTK_WIDGET(text_tool)); } static gint text_delete_callback (GtkWidget *w, GdkEvent *e, gpointer client_data) { text_cancel_callback (w, client_data); return FALSE; } static void text_cancel_callback (GtkWidget *w, gpointer client_data) { GnomeFontSelector * text_tool; text_tool = GNOME_FONT_SELECTOR(client_data); if (GTK_WIDGET_VISIBLE (text_tool)) gtk_widget_hide (GTK_WIDGET(text_tool)); } static void text_font_item_update (GtkWidget *w, gpointer data) { FontInfo *font; int old_index; int i, index; GnomeFontSelector *the_text_tool; GnomeFontSelectorClass *klass; FontInfo **font_info; /* Is this font being selected? */ if (w->state != GTK_STATE_SELECTED) return; the_text_tool = GNOME_FONT_SELECTOR(gtk_object_get_data(GTK_OBJECT(w), "GnomeFontSelector")); klass = GNOME_FONT_SELECTOR_CLASS(GTK_OBJECT(the_text_tool)->klass); font_info = klass->font_info; index = (long) data; old_index = the_text_tool->font_index; the_text_tool->font_index = index; if (!text_load_font (the_text_tool)) { the_text_tool->font_index = old_index; return; } font = font_info[the_text_tool->font_index]; if (the_text_tool->foundry && !font->foundries[the_text_tool->foundry]) { the_text_tool->foundry = 0; gtk_option_menu_set_history (GTK_OPTION_MENU (the_text_tool->option_menus[0]), 0); } if (the_text_tool->weight && !font->weights[the_text_tool->weight]) { the_text_tool->weight = 0; gtk_option_menu_set_history (GTK_OPTION_MENU (the_text_tool->option_menus[1]), 0); } if (the_text_tool->slant && !font->slants[the_text_tool->slant]) { the_text_tool->slant = 0; gtk_option_menu_set_history (GTK_OPTION_MENU (the_text_tool->option_menus[2]), 0); } if (the_text_tool->set_width && !font->set_widths[the_text_tool->set_width]) { the_text_tool->set_width = 0; gtk_option_menu_set_history (GTK_OPTION_MENU (the_text_tool->option_menus[3]), 0); } if (the_text_tool->spacing && !font->spacings[the_text_tool->spacing]) { the_text_tool->spacing = 0; gtk_option_menu_set_history (GTK_OPTION_MENU (the_text_tool->option_menus[4]), 0); } for (i = 0; i < klass->nfoundries; i++) gtk_widget_set_sensitive (the_text_tool->foundry_items[i], font->foundries[i]); for (i = 0; i < klass->nweights; i++) gtk_widget_set_sensitive (the_text_tool->weight_items[i], font->weights[i]); for (i = 0; i < klass->nslants; i++) gtk_widget_set_sensitive (the_text_tool->slant_items[i], font->slants[i]); for (i = 0; i < klass->nset_widths; i++) gtk_widget_set_sensitive (the_text_tool->set_width_items[i], font->set_widths[i]); for (i = 0; i < klass->nspacings; i++) gtk_widget_set_sensitive (the_text_tool->spacing_items[i], font->spacings[i]); } static void text_pixels_callback (GtkWidget *w, gpointer client_data) { GnomeFontSelector *text_tool; int old_value; text_tool = GNOME_FONT_SELECTOR(client_data); old_value = text_tool->size_type; text_tool->size_type = PIXELS; if (!text_load_font (text_tool)) text_tool->size_type = old_value; } #if 0 /* Commented out until used. Is this useful? */ static void text_points_callback (GtkWidget *w, gpointer client_data) { GnomeFontSelector *text_tool; int old_value; text_tool = GNOME_FONT_SELECTOR(client_data); old_value = text_tool->size_type; text_tool->size_type = POINTS; if (!text_load_font (text_tool)) text_tool->size_type = old_value; } #endif static void text_foundry_callback (GtkWidget *w, gpointer client_data) { int old_value; GnomeFontSelector *the_text_tool; the_text_tool = GNOME_FONT_SELECTOR(gtk_object_get_data(GTK_OBJECT(w), "GnomeFontSelector")); old_value = the_text_tool->foundry; the_text_tool->foundry = (long) client_data; text_validate_combo (the_text_tool, 0); if (!text_load_font (the_text_tool)) the_text_tool->foundry = old_value; } static void text_weight_callback (GtkWidget *w, gpointer client_data) { int old_value; GnomeFontSelector *the_text_tool; the_text_tool = GNOME_FONT_SELECTOR(gtk_object_get_data(GTK_OBJECT(w), "GnomeFontSelector")); old_value = the_text_tool->weight; the_text_tool->weight = (long) client_data; text_validate_combo (the_text_tool, 1); if (!text_load_font (the_text_tool)) the_text_tool->weight = old_value; } static void text_slant_callback (GtkWidget *w, gpointer client_data) { int old_value; GnomeFontSelector *the_text_tool; the_text_tool = GNOME_FONT_SELECTOR(gtk_object_get_data(GTK_OBJECT(w), "GnomeFontSelector")); old_value = the_text_tool->slant; the_text_tool->slant = (long) client_data; text_validate_combo (the_text_tool, 2); if (!text_load_font (the_text_tool)) the_text_tool->slant = old_value; } static void text_set_width_callback (GtkWidget *w, gpointer client_data) { int old_value; GnomeFontSelector *the_text_tool; the_text_tool = GNOME_FONT_SELECTOR(gtk_object_get_data(GTK_OBJECT(w), "GnomeFontSelector")); old_value = the_text_tool->set_width; the_text_tool->set_width = (long) client_data; text_validate_combo (the_text_tool, 3); if (!text_load_font (the_text_tool)) the_text_tool->set_width = old_value; } static void text_spacing_callback (GtkWidget *w, gpointer client_data) { int old_value; GnomeFontSelector *the_text_tool; the_text_tool = GNOME_FONT_SELECTOR(gtk_object_get_data(GTK_OBJECT(w), "GnomeFontSelector")); old_value = the_text_tool->spacing; the_text_tool->spacing = (long) client_data; text_validate_combo (the_text_tool, 4); if (!text_load_font (the_text_tool)) the_text_tool->spacing = old_value; } static gint text_size_key_function (GtkWidget *w, GdkEventKey *event, gpointer data) { GnomeFontSelector *text_tool; gchar buffer[16]; gint old_value; text_tool = (GnomeFontSelector *) data; if (event->keyval == GDK_Return) { gtk_signal_emit_stop_by_name (GTK_OBJECT (w), "key_press_event"); old_value = atoi (gtk_entry_get_text (GTK_ENTRY (text_tool->size_text))); if (!text_load_font (text_tool)) { g_snprintf (buffer, sizeof(buffer), "%d", old_value); gtk_entry_set_text (GTK_ENTRY (text_tool->size_text), buffer); } return TRUE; } return FALSE; } static void text_validate_combo (GnomeFontSelector *text_tool, gint which) { FontInfo *font; int which_val; int new_combo[5]; int best_combo[5]; int best_matches; int matches; int i; GnomeFontSelectorClass *klass; FontInfo **font_info; klass = GNOME_FONT_SELECTOR_CLASS(GTK_OBJECT(text_tool)->klass); font_info = klass->font_info; font = font_info[text_tool->font_index]; switch (which) { case 0: which_val = text_tool->foundry; break; case 1: which_val = text_tool->weight; break; case 2: which_val = text_tool->slant; break; case 3: which_val = text_tool->set_width; break; case 4: which_val = text_tool->spacing; break; default: which_val = 0; break; } best_matches = -1; best_combo[0] = 0; best_combo[1] = 0; best_combo[2] = 0; best_combo[3] = 0; best_combo[4] = 0; for (i = 0; i < font->ncombos; i++) { /* we must match the which field */ if (font->combos[i][which] == which_val) { matches = 0; new_combo[0] = 0; new_combo[1] = 0; new_combo[2] = 0; new_combo[3] = 0; new_combo[4] = 0; if ((text_tool->foundry == 0) || (text_tool->foundry == font->combos[i][0])) { matches++; if (text_tool->foundry) new_combo[0] = font->combos[i][0]; } if ((text_tool->weight == 0) || (text_tool->weight == font->combos[i][1])) { matches++; if (text_tool->weight) new_combo[1] = font->combos[i][1]; } if ((text_tool->slant == 0) || (text_tool->slant == font->combos[i][2])) { matches++; if (text_tool->slant) new_combo[2] = font->combos[i][2]; } if ((text_tool->set_width == 0) || (text_tool->set_width == font->combos[i][3])) { matches++; if (text_tool->set_width) new_combo[3] = font->combos[i][3]; } if ((text_tool->spacing == 0) || (text_tool->spacing == font->combos[i][4])) { matches++; if (text_tool->spacing) new_combo[4] = font->combos[i][4]; } /* if we get all 5 matches simply return */ if (matches == 5) return; if (matches > best_matches) { best_matches = matches; best_combo[0] = new_combo[0]; best_combo[1] = new_combo[1]; best_combo[2] = new_combo[2]; best_combo[3] = new_combo[3]; best_combo[4] = new_combo[4]; } } } if (best_matches > -1) { if (text_tool->foundry != best_combo[0]) { text_tool->foundry = best_combo[0]; if (which != 0) gtk_option_menu_set_history (GTK_OPTION_MENU (text_tool->option_menus[0]), text_tool->foundry); } if (text_tool->weight != best_combo[1]) { text_tool->weight = best_combo[1]; if (which != 1) gtk_option_menu_set_history (GTK_OPTION_MENU (text_tool->option_menus[1]), text_tool->weight); } if (text_tool->slant != best_combo[2]) { text_tool->slant = best_combo[2]; if (which != 2) gtk_option_menu_set_history (GTK_OPTION_MENU (text_tool->option_menus[2]), text_tool->slant); } if (text_tool->set_width != best_combo[3]) { text_tool->set_width = best_combo[3]; if (which != 3) gtk_option_menu_set_history (GTK_OPTION_MENU (text_tool->option_menus[3]), text_tool->set_width); } if (text_tool->spacing != best_combo[4]) { text_tool->spacing = best_combo[4]; if (which != 4) gtk_option_menu_set_history (GTK_OPTION_MENU (text_tool->option_menus[4]), text_tool->spacing); } } } static void text_get_fonts (GnomeFontSelectorClass *klass) { gchar **fontnames; gchar *fontname; gchar *field; GSList * temp_list; gint num_fonts; gint index; gint i, j; /* construct a valid font pattern */ fontnames = XListFonts (GDK_DISPLAY(), "-*-*-*-*-*-*-0-0-75-75-*-0-*-*", 32767, &num_fonts); /* the maximum size of the table is the number of font names returned */ klass->font_info = g_malloc (sizeof (FontInfo**) * num_fonts); /* insert the fontnames into a table */ klass->nfonts = 0; for (i = 0; i < num_fonts; i++) if (text_is_xlfd_font_name (fontnames[i])) { text_insert_font (klass->font_info, &klass->nfonts, fontnames[i]); klass->foundries = text_insert_field (klass->foundries, fontnames[i], FOUNDRY); klass->weights = text_insert_field (klass->weights, fontnames[i], WEIGHT); klass->slants = text_insert_field (klass->slants, fontnames[i], SLANT); klass->set_widths = text_insert_field (klass->set_widths, fontnames[i], SET_WIDTH); klass->spacings = text_insert_field (klass->spacings, fontnames[i], SPACING); } XFreeFontNames (fontnames); #define list_length g_slist_length klass->nfoundries = list_length (klass->foundries) + 1; klass->nweights = list_length (klass->weights) + 1; klass->nslants = list_length (klass->slants) + 1; klass->nset_widths = list_length (klass->set_widths) + 1; klass->nspacings = list_length (klass->spacings) + 1; klass->foundry_array = g_malloc (sizeof (char*) * klass->nfoundries); klass->weight_array = g_malloc (sizeof (char*) * klass->nweights); klass->slant_array = g_malloc (sizeof (char*) * klass->nslants); klass->set_width_array = g_malloc (sizeof (char*) * klass->nset_widths); klass->spacing_array = g_malloc (sizeof (char*) * klass->nspacings); i = 1; temp_list = klass->foundries; while (temp_list) { klass->foundry_array[i++] = temp_list->data; temp_list = temp_list->next; } i = 1; temp_list = klass->weights; while (temp_list) { klass->weight_array[i++] = temp_list->data; temp_list = temp_list->next; } i = 1; temp_list = klass->slants; while (temp_list) { klass->slant_array[i++] = temp_list->data; temp_list = temp_list->next; } i = 1; temp_list = klass->set_widths; while (temp_list) { klass->set_width_array[i++] = temp_list->data; temp_list = temp_list->next; } i = 1; temp_list = klass->spacings; while (temp_list) { klass->spacing_array[i++] = temp_list->data; temp_list = temp_list->next; } klass->foundry_array[0] = "*"; klass->weight_array[0] = "*"; klass->slant_array[0] = "*"; klass->set_width_array[0] = "*"; klass->spacing_array[0] = "*"; for (i = 0; i < klass->nfonts; i++) { klass->font_info[i]->foundries = g_malloc (sizeof (int) * klass->nfoundries); klass->font_info[i]->weights = g_malloc (sizeof (int) * klass->nweights); klass->font_info[i]->slants = g_malloc (sizeof (int) * klass->nslants); klass->font_info[i]->set_widths = g_malloc (sizeof (int) * klass->nset_widths); klass->font_info[i]->spacings = g_malloc (sizeof (int) * klass->nspacings); klass->font_info[i]->ncombos = list_length (klass->font_info[i]->fontnames); klass->font_info[i]->combos = g_malloc (sizeof (int*) * klass->font_info[i]->ncombos); for (j = 0; j < klass->nfoundries; j++) klass->font_info[i]->foundries[j] = 0; for (j = 0; j < klass->nweights; j++) klass->font_info[i]->weights[j] = 0; for (j = 0; j < klass->nslants; j++) klass->font_info[i]->slants[j] = 0; for (j = 0; j < klass->nset_widths; j++) klass->font_info[i]->set_widths[j] = 0; for (j = 0; j < klass->nspacings; j++) klass->font_info[i]->spacings[j] = 0; klass->font_info[i]->foundries[0] = 1; klass->font_info[i]->weights[0] = 1; klass->font_info[i]->slants[0] = 1; klass->font_info[i]->set_widths[0] = 1; klass->font_info[i]->spacings[0] = 1; j = 0; temp_list = klass->font_info[i]->fontnames; while (temp_list) { fontname = temp_list->data; temp_list = temp_list->next; klass->font_info[i]->combos[j] = g_malloc (sizeof (int) * 5); field = text_get_field (fontname, FOUNDRY); index = text_field_to_index (klass->foundry_array, klass->nfoundries, field); klass->font_info[i]->foundries[index] = 1; klass->font_info[i]->combos[j][0] = index; g_free (field); field = text_get_field (fontname, WEIGHT); index = text_field_to_index (klass->weight_array, klass->nweights, field); klass->font_info[i]->weights[index] = 1; klass->font_info[i]->combos[j][1] = index; g_free (field); field = text_get_field (fontname, SLANT); index = text_field_to_index (klass->slant_array, klass->nslants, field); klass->font_info[i]->slants[index] = 1; klass->font_info[i]->combos[j][2] = index; g_free (field); field = text_get_field (fontname, SET_WIDTH); index = text_field_to_index (klass->set_width_array, klass->nset_widths, field); klass->font_info[i]->set_widths[index] = 1; klass->font_info[i]->combos[j][3] = index; g_free (field); field = text_get_field (fontname, SPACING); index = text_field_to_index (klass->spacing_array, klass->nspacings, field); klass->font_info[i]->spacings[index] = 1; klass->font_info[i]->combos[j][4] = index; g_free (field); j += 1; } } } static void text_insert_font (FontInfo **table, gint *ntable, const gchar *fontname) { FontInfo *temp_info; gchar *family; gint lower, upper; gint middle, cmp; /* insert a fontname into a table */ family = text_get_field (fontname, FAMILY); if (!family) return; lower = 0; if (*ntable > 0) { /* Do a binary search to determine if we have already encountered * a font from this family. */ upper = *ntable; while (lower < upper) { middle = (lower + upper) >> 1; cmp = strcmp (family, table[middle]->family); if (cmp == 0) { table[middle]->fontnames = g_slist_prepend (table[middle]->fontnames, g_strdup (fontname)); return; } else if (cmp < 0) upper = middle; else if (cmp > 0) lower = middle+1; } } /* Add another entry to the table for this new font family */ table[*ntable] = g_malloc (sizeof (FontInfo)); table[*ntable]->family = family; table[*ntable]->foundries = NULL; table[*ntable]->weights = NULL; table[*ntable]->slants = NULL; table[*ntable]->set_widths = NULL; table[*ntable]->fontnames = NULL; table[*ntable]->fontnames = g_slist_prepend (table[*ntable]->fontnames, g_strdup (fontname)); (*ntable)++; /* Quickly insert the entry into the table in sorted order * using a modification of insertion sort and the knowledge * that the entries proper position in the table was determined * above in the binary search and is contained in the "lower" * variable. */ if (*ntable > 1) { temp_info = table[*ntable - 1]; upper = *ntable - 1; while (lower != upper) { table[upper] = table[upper-1]; upper -= 1; } table[lower] = temp_info; } } static GSList * text_insert_field (GSList *list, const gchar *fontname, gint field_num) { GSList *temp_list; GSList *prev_list; GSList *new_list; gchar *field; gint cmp; field = text_get_field (fontname, field_num); if (!field) return list; temp_list = list; prev_list = NULL; while (temp_list) { cmp = strcmp (field, temp_list->data); if (cmp == 0) { g_free (field); return list; } else if (cmp < 0) { new_list = g_slist_alloc (); new_list->data = field; new_list->next = temp_list; if (prev_list) { prev_list->next = new_list; return list; } else return new_list; } else { prev_list = temp_list; temp_list = temp_list->next; } } new_list = g_slist_alloc (); new_list->data = field; new_list->next = NULL; if (prev_list) { prev_list->next = new_list; return list; } else return new_list; } static gchar* text_get_field (const gchar *fontname, gint field_num) { const gchar *t1, *t2; gchar *field; /* we assume this is a valid fontname...that is, it has 14 fields */ t1 = fontname; while (*t1 && (field_num >= 0)) if (*t1++ == '-') field_num--; t2 = t1; while (*t2 && (*t2 != '-')) t2++; if (t1 != t2) { field = g_malloc (1 + (long) t2 - (long) t1); strncpy (field, t1, (long) t2 - (long) t1); field[(long) t2 - (long) t1] = 0; return field; } return g_strdup ("(nil)"); } static int text_field_to_index (gchar **table, gint ntable, const gchar *field) { gint i; for (i = 0; i < ntable; i++) if (strcmp (field, table[i]) == 0) return i; return -1; } static gint text_is_xlfd_font_name (const gchar *fontname) { gint i; i = 0; while (*fontname) if (*fontname++ == '-') i++; return (i == 14); } static gchar * text_get_xlfd (gdouble size, gint size_type, const gchar *foundry, const gchar *family, const gchar *weight, const gchar *slant, const gchar *set_width, const gchar *spacing) { gchar pixel_size[12], point_size[12]; if (size > 0) { switch (size_type) { case PIXELS: g_snprintf (pixel_size, sizeof(pixel_size), "%d", (int) size); g_snprintf (point_size, sizeof(point_size), "*"); break; case POINTS: g_snprintf (pixel_size, sizeof(pixel_size), "*"); g_snprintf (point_size, sizeof(point_size), "%d", (int) (size * 10)); break; } return g_strconcat("-", foundry, "-", family, "-", weight, "-", slant, "-", set_width, "-*-", pixel_size, "-", point_size, "-75-75-", spacing, "-*-*-*", NULL); } else return NULL; } static gint text_load_font (GnomeFontSelector *text_tool) { GdkFont *font; gchar *fontname; gdouble size; gchar *size_text; gchar *foundry_str; gchar *family_str; gchar *weight_str; gchar *slant_str; gchar *set_width_str; gchar *spacing_str; GnomeFontSelectorClass *klass; klass = GNOME_FONT_SELECTOR_CLASS(GTK_OBJECT(text_tool)->klass); size_text = gtk_entry_get_text (GTK_ENTRY (text_tool->size_text)); size = atof (size_text); foundry_str = klass->foundry_array[text_tool->foundry]; if (strcmp (foundry_str, "(nil)") == 0) foundry_str = ""; family_str = klass->font_info[text_tool->font_index]->family; weight_str = klass->weight_array[text_tool->weight]; if (strcmp (weight_str, "(nil)") == 0) weight_str = ""; slant_str = klass->slant_array[text_tool->slant]; if (strcmp (slant_str, "(nil)") == 0) slant_str = ""; set_width_str = klass->set_width_array[text_tool->set_width]; if (strcmp (set_width_str, "(nil)") == 0) set_width_str = ""; spacing_str = klass->spacing_array[text_tool->spacing]; if (strcmp (spacing_str, "(nil)") == 0) spacing_str = ""; if ((fontname = text_get_xlfd (size, text_tool->size_type, foundry_str, family_str, weight_str, slant_str, set_width_str, spacing_str))) { font = gdk_font_load (fontname); g_free(fontname); if (font) { if (text_tool->font) gdk_font_unref (text_tool->font); text_tool->font = font; text_resize_text_widget (text_tool); return TRUE; } } return FALSE; } /** * gnome_font_selector_get_selected: * @text_tool: a font selector * * Returns the name of the font currently selected. The value returned * is allocated with g_malloc. The font name is in the format expected * by Gdk. */ gchar * gnome_font_selector_get_selected (GnomeFontSelector *text_tool) { gdouble size; gchar *size_text; gchar *foundry_str; gchar *family_str; gchar *weight_str; gchar *slant_str; gchar *set_width_str; gchar *spacing_str; GnomeFontSelectorClass *klass; klass = GNOME_FONT_SELECTOR_CLASS(GTK_OBJECT(text_tool)->klass); size_text = gtk_entry_get_text (GTK_ENTRY (text_tool->size_text)); size = atof (size_text); foundry_str = klass->foundry_array[text_tool->foundry]; if (strcmp (foundry_str, "(nil)") == 0) foundry_str = ""; family_str = klass->font_info[text_tool->font_index]->family; weight_str = klass->weight_array[text_tool->weight]; if (strcmp (weight_str, "(nil)") == 0) weight_str = ""; slant_str = klass->slant_array[text_tool->slant]; if (strcmp (slant_str, "(nil)") == 0) slant_str = ""; set_width_str = klass->set_width_array[text_tool->set_width]; if (strcmp (set_width_str, "(nil)") == 0) set_width_str = ""; spacing_str = klass->spacing_array[text_tool->spacing]; if (strcmp (spacing_str, "(nil)") == 0) spacing_str = ""; return text_get_xlfd (size, text_tool->size_type, foundry_str, family_str, weight_str, slant_str, set_width_str, spacing_str); } static void gnome_font_select_quit(GtkWidget *widget, gpointer user_data) { gtk_main_quit(); gtk_object_set_data(GTK_OBJECT(user_data), "gnome_font_select_quit widget", widget); } /** * gnome_font_select: * * Pops up a font selector and lets the user choose the font. * * Returns: A g_malloc()ed string with the X font name that was selected */ gchar * gnome_font_select(void) { GnomeFontSelector *font_sel; gchar *retval = NULL; font_sel = GNOME_FONT_SELECTOR(gnome_font_selector_new()); gtk_signal_connect(GTK_OBJECT(font_sel->ok_button), "clicked", GTK_SIGNAL_FUNC(gnome_font_select_quit), font_sel); gtk_signal_connect(GTK_OBJECT(font_sel->cancel_button), "clicked", GTK_SIGNAL_FUNC(gnome_font_select_quit), font_sel); gtk_signal_connect(GTK_OBJECT(font_sel), "delete_event", GTK_SIGNAL_FUNC(gnome_font_select_quit), font_sel); gtk_widget_show(GTK_WIDGET(font_sel)); gtk_grab_add(GTK_WIDGET(font_sel)); gtk_main(); gtk_widget_hide(GTK_WIDGET(font_sel)); gtk_grab_remove(GTK_WIDGET(font_sel)); if(gtk_object_get_data(GTK_OBJECT(font_sel), "gnome_font_select_quit widget") == font_sel->ok_button) retval = gnome_font_selector_get_selected(font_sel); gtk_widget_destroy(GTK_WIDGET(font_sel)); return retval; } /** * gnome_font_select: * @default_font: The font chosen by default. * * Pops up a font selector and lets the user choose the font. * * Returns: A g_malloc()ed string with the X font name that was selected */ gchar *gnome_font_select_with_default(const gchar *default_font) { GnomeFontSelector *text_tool; gchar *retval = NULL; text_tool = GNOME_FONT_SELECTOR(gnome_font_selector_new()); /* If it is a valid font name ... */ if (default_font && text_is_xlfd_font_name (default_font)) { char *foundry, *family, *weight, *slant, *set_width, *spacing; char *pixel_size, *point_size; int old_value, old_size, i; GnomeFontSelectorClass *klass = GNOME_FONT_SELECTOR_CLASS (GTK_OBJECT (text_tool)->klass); foundry = text_get_field (default_font, FOUNDRY); family = text_get_field (default_font, FAMILY); weight = text_get_field (default_font, WEIGHT); slant = text_get_field (default_font, SLANT); set_width = text_get_field (default_font, SET_WIDTH); pixel_size = text_get_field (default_font, 6); point_size = text_get_field (default_font, 7); spacing = text_get_field (default_font, SPACING); /* set family. */ old_value = text_tool->font_index; for (i = 0; i < klass->nfonts; i++) if (!strcmp (family, klass->font_info[i]->family)) { text_tool->font_index = i; break; } if (!text_load_font (text_tool)) text_tool->font_index = old_value; gtk_list_select_item (GTK_LIST (text_tool->font_list), text_tool->font_index); /* set foundry. */ old_value = text_tool->foundry; text_tool->foundry = text_field_to_index (klass->foundry_array, klass->nfoundries, foundry); text_validate_combo (text_tool, 0); if (!text_load_font (text_tool)) text_tool->foundry = old_value; gtk_option_menu_set_history (GTK_OPTION_MENU (text_tool->option_menus [0]), text_tool->foundry); /* set weight. */ old_value = text_tool->weight; text_tool->weight = text_field_to_index (klass->weight_array, klass->nweights, weight); text_validate_combo (text_tool, 1); if (!text_load_font (text_tool)) text_tool->weight = old_value; gtk_option_menu_set_history (GTK_OPTION_MENU (text_tool->option_menus [1]), text_tool->weight); /* set slant. */ old_value = text_tool->slant; text_tool->slant = text_field_to_index (klass->slant_array, klass->nslants, slant); text_validate_combo (text_tool, 2); if (!text_load_font (text_tool)) text_tool->slant = old_value; gtk_option_menu_set_history (GTK_OPTION_MENU (text_tool->option_menus [2]), text_tool->slant); /* set width. */ old_value = text_tool->set_width; text_tool->set_width = text_field_to_index (klass->set_width_array, klass->nset_widths, set_width); text_validate_combo (text_tool, 3); if (!text_load_font (text_tool)) text_tool->set_width = old_value; gtk_option_menu_set_history (GTK_OPTION_MENU (text_tool->option_menus [3]), text_tool->set_width); /* set spacing. */ old_value = text_tool->spacing; text_tool->spacing = text_field_to_index (klass->spacing_array, klass->nspacings, spacing); text_validate_combo (text_tool, 4); if (!text_load_font (text_tool)) text_tool->spacing = old_value; gtk_option_menu_set_history (GTK_OPTION_MENU (text_tool->option_menus [4]), text_tool->spacing); /* first we try to set the pixel size and then the point size. */ old_value = text_tool->size_type; old_size = atoi (gtk_entry_get_text (GTK_ENTRY (text_tool->size_text))); if (strcmp (pixel_size, "*") && strcmp (pixel_size, "(nil)")) { text_tool->size_type = PIXELS; gtk_entry_set_text (GTK_ENTRY (text_tool->size_text), pixel_size); if (!text_load_font (text_tool)) { char buffer [BUFSIZ]; text_tool->size_type = old_value; g_snprintf (buffer, sizeof(buffer), "%d", old_size); gtk_entry_set_text (GTK_ENTRY (text_tool->size_text), buffer); } } } gtk_signal_connect(GTK_OBJECT(text_tool->ok_button), "clicked", GTK_SIGNAL_FUNC(gnome_font_select_quit), text_tool); gtk_signal_connect(GTK_OBJECT(text_tool->cancel_button), "clicked", GTK_SIGNAL_FUNC(gnome_font_select_quit), text_tool); gtk_signal_connect(GTK_OBJECT(text_tool), "delete_event", GTK_SIGNAL_FUNC(gnome_font_select_quit), text_tool); gtk_widget_show(GTK_WIDGET(text_tool)); gtk_grab_add(GTK_WIDGET(text_tool)); gtk_main(); gtk_widget_hide(GTK_WIDGET(text_tool)); gtk_grab_remove(GTK_WIDGET(text_tool)); if(gtk_object_get_data(GTK_OBJECT(text_tool), "gnome_font_select_quit widget") == text_tool->ok_button) retval = gnome_font_selector_get_selected(text_tool); gtk_widget_destroy(GTK_WIDGET(text_tool)); return retval; }