home *** CD-ROM | disk | FTP | other *** search
- /* kern.c: manipulate the kerning table.
-
- Copyright (C) 1992 Free Software Foundation, Inc.
-
- 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "config.h"
-
- #include <ctype.h>
- #include "xt-common.h"
- #include "Item.h"
- #include "xmessage.h"
-
- #include "char.h"
- #include "kern.h"
- #include "main.h"
-
- static int find_char_in_kern_list (list_type, charcode_type);
-
- /* Change the kern value for the current character in the font
- CLIENT_DATA, followed by the character given by W's label, to be
- CALL_DATA. */
-
- void
- change_kern_callback (Widget w, XtPointer client_data, XtPointer call_data)
- {
- string value_string = call_data;
-
- /* We should end up at the null terminator. */
- if (!float_ok (value_string))
- {
- string s = concat3 ("`", value_string, "': invalid real");
- x_warning (XtParent (XtParent (w)), s);
- free (s);
- }
- else
- { /* The value they typed is ok. */
- charcode_type kern_char;
- unsigned u;
- font_type *f = (font_type *) client_data;
- char_type *c = FONT_CURRENT_CHAR (*f);
-
- string label_string = ItemGetLabelString (w);
-
- real kern_value = PIXELS_TO_POINTS (atof (value_string), FONT_DPI (*f));
-
- /* Extract the character code out of the item label. */
- assert (sscanf (label_string, "%u: ", &u) == 1);
- kern_char = u;
-
- /* Update an existing value, or add a new one. */
- tfm_set_kern (&TFM_KERN (CHAR_TFM_INFO (*c)), kern_char, kern_value);
-
- FONT_MODIFIED (*f) = true;
- }
- }
-
- /* Add a new kern between the current character and the one specified in
- CALL_DATA. Give it initial value zero (the user can edit the new
- value as usual once it exists). */
-
- void
- add_kern_callback (Widget w, XtPointer client_data, XtPointer call_data)
- {
- charcode_type code;
- string value_string = call_data;
-
- if (XTPARSE_CHARCODE (code, value_string, w))
- {
- font_type *f = (font_type *) client_data;
- char_type *c = FONT_CURRENT_CHAR (*f);
- tfm_char_type tfm_char = CHAR_TFM_INFO (*c);
- list_type kern_list = tfm_char.kern;
-
- if (find_char_in_kern_list (kern_list, code) >= 0)
- x_warning (XtParent (w), "Already in kern list");
- else
- {
- Widget kern_box;
-
- /* Add the kern element to the font. */
- tfm_set_kern (&TFM_KERN (CHAR_TFM_INFO (*c)), code, 0.0);
- FONT_MODIFIED (*f) = true;
-
- /* Make the new widget. */
- kern_box = XFIND_WIDGET (XtParent (w), "kern box");
- add_kern_widget (kern_box, f, code, 0.0);
- }
-
- /* Clear the character code we just processed from the Item. */
- XtVaSetValues (w, XtNvalue, "", NULL, NULL);
- }
- }
-
-
- /* Create a new Item widget for editing a kern with character CODE in
- font F and value KERN points. Add the new widget to BOX. */
-
- /* The length here is 1 for a possible sign, 2 for the integer part, the
- decimal point, and 1 for the fractional part. We're assuming no kern
- will have magnitude > 99.9 pixels. If this fails, the toolkit will
- give an error about the length not being long enough. */
- #define KERN_VALUE_WIDTH 5
-
- void
- add_kern_widget (Widget box, font_type *f, charcode_type code, real kern)
- {
- char name[MAX_INT_LENGTH + 6];
- char val[MAX_INT_LENGTH + 4];
- string code_string = xmalloc (MAX_INT_LENGTH + 2);
- XtCallbackRec change_kern_callbacks[]
- = SINGLE_CALLBACK (change_kern_callback, f);
- Arg kern_args[]
- = { { XtNlabel, (XtArgVal) NULL }, /* Assigned below. */
- { XtNvalue, (XtArgVal) NULL },
- { XtNcallback, (XtArgVal) change_kern_callbacks },
- { XtNlength, (XtArgVal) KERN_VALUE_WIDTH },
- };
-
- sprintf (code_string, "%u: ", code);
- XTASSIGN_ARG (kern_args[0], code_string);
-
- /* We can't use `POINTS_TO_PIXELS' here, since that rounds to the
- nearest whole number of pixels, and we want fractional pixels. */
- sprintf (val, "%.1f", kern * FONT_DPI (*f) / POINTS_PER_INCH);
- XTASSIGN_ARG (kern_args[1], val);
-
- sprintf (name, "kern %u", code);
- (void) XtCreateManagedWidget (name, itemWidgetClass, box, XTARG (kern_args));
- }
-
- /* Remove an existing kern between the current character and the one
- specified in CALL_DATA. */
-
- void
- remove_kern_callback (Widget w, XtPointer client_data, XtPointer call_data)
- {
- charcode_type code;
- string value_string = call_data;
-
- if (XTPARSE_CHARCODE (code, value_string, w))
- {
- font_type *f = (font_type *) client_data;
- char_type *c = FONT_CURRENT_CHAR (*f);
- list_type *kern_list = &(CHAR_TFM_INFO (*c).kern);
- int loc = find_char_in_kern_list (*kern_list, code);
-
- if (loc < 0)
- x_warning (XtParent (w), "Not in kern list");
- else
- {
- unsigned e;
- char kern_name[7 + MAX_INT_LENGTH];
-
- /* Remove the kern from the list in the font. */
- free (LIST_ELT (*kern_list, loc));
- for (e = loc + 1; e < LIST_SIZE (*kern_list); e++)
- LIST_ELT (*kern_list, e - 1) = LIST_ELT (*kern_list, e);
- LIST_SIZE (*kern_list)--;
-
- /* Get rid of the widget. We need the `*' to find the name,
- since the kern items aren't children of the Form, they are
- children of a Box which is a child of the Form. */
- sprintf (kern_name, "*kern %u", code);
- XtDestroyWidget (XFIND_WIDGET (XtParent (w), kern_name));
-
- /* Clear the character code we just processed from the Item. */
- XtVaSetValues (w, XtNvalue, "", NULL, NULL);
-
- FONT_MODIFIED (*f) = true;
- }
- }
- }
-
-
- /* Return the index of the element in KERN_LIST which has code CODE, or
- -1 if no such kern is in KERN_LIST. */
-
- static int
- find_char_in_kern_list (list_type kern_list, charcode_type code)
- {
- unsigned e;
-
- for (e = 0; e < LIST_SIZE (kern_list); e++)
- {
- tfm_kern_type *k = LIST_ELT (kern_list, e);
-
- if (k->character == code)
- return e;
- }
-
- return -1;
- }
-
- /* Return the maximum width of a kern item. Since there may not be any
- kern items extant, we can't just find one and ask for its widget
- width. Instead, we look up the font resources in the database
- (using the widget TOP as a handle) and then compute the width
- with the X text routines. */
-
- unsigned
- find_kern_item_width (Widget top)
- {
- XrmValue db_value;
- XFontStruct *f;
- string font_name;
- int kern_width, label_width;
- Dimension label_internal_width;
- string rep_type;
- Display *d = XtDisplay (top);
- XrmDatabase db = XtDatabase (d);
-
- string class = CLASS_NAME ".Box.Item.Label.Font";
- string name = concat (XtName (top), ".kern box.kern 0.item label.font");
-
- /* Find the max width of the label. The string here is what is used
- in `add_kern_widget', above. We assume that 0 is as wide as any
- other number. This assertion and the one below are ok because we
- should never be using the server default font for these items. To
- be absolutely safe, we should look up XtDefaultFont if this fails,
- but it hardly seems worth it. */
- assert (XrmGetResource (db, name, class, &rep_type, &db_value));
-
- /* Retrieve the font structure. */
- font_name = db_value.addr;
- f = XLoadQueryFont (d, font_name);
-
- /* Find the width. Assume no nulls in TEXT. */
- label_width = XTextWidth (f, "000: ", 5);
-
- /* Free the memory used. */
- XFreeFont (d, f);
- free (name);
-
-
- /* Find the max width of the value. Here we must use the same
- algorithm the Item does for its value subwidget: multiply the
- length of the text by the maximum width from the font bounding box. */
- class = CLASS_NAME ".Box.Item.Text.Font";
- name = concat (XtName (top), ".kern box.kern 0.item value.font");
- assert (XrmGetResource (db, name, class, &rep_type, &db_value));
-
- /* Retrieve the font structure. */
- font_name = db_value.addr;
- f = XLoadQueryFont (d, font_name);
- kern_width
- = KERN_VALUE_WIDTH * (f->max_bounds.rbearing - f->min_bounds.lbearing);
-
- /* Free the memory used. */
- XFreeFont (d, f);
- free (name);
-
-
- /* Last thing: look up the internal width of the label subwidget of
- the Item, so we can add that in. We assume the margins on the
- value subwidget are zero, and that the borders are zero. */
- class = CLASS_NAME ".Box.Item.Label.Width";
- name = concat (XtName (top), ".kern box.kern 0.item label.internalWidth");
- label_internal_width
- = XrmGetResource (db, name, class, &rep_type, &db_value)
- ? atoi (db_value.addr)
- : 4; /* The Label widget's default. */
- free (name);
-
- return label_width + label_internal_width * 2 + kern_width;
- }
-