home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / fontutils-0.6-base.tgz / fontutils-0.6-base.tar / fsf / fontutils / xbfe / kern.c < prev    next >
C/C++ Source or Header  |  1992-06-21  |  9KB  |  279 lines

  1. /* kern.c: manipulate the kerning table.
  2.  
  3. Copyright (C) 1992 Free Software Foundation, Inc.
  4.  
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <ctype.h>
  22. #include "xt-common.h"
  23. #include "Item.h"
  24. #include "xmessage.h"
  25.  
  26. #include "char.h"
  27. #include "kern.h"
  28. #include "main.h"
  29.  
  30. static int find_char_in_kern_list (list_type, charcode_type);
  31.  
  32. /* Change the kern value for the current character in the font
  33.    CLIENT_DATA, followed by the character given by W's label, to be
  34.    CALL_DATA.  */
  35.  
  36. void
  37. change_kern_callback (Widget w, XtPointer client_data, XtPointer call_data)
  38. {
  39.   string value_string = call_data;
  40.  
  41.   /* We should end up at the null terminator.  */
  42.   if (!float_ok (value_string))
  43.     {
  44.       string s = concat3 ("`", value_string, "': invalid real");
  45.       x_warning (XtParent (XtParent (w)), s);
  46.       free (s);
  47.     }
  48.   else
  49.     { /* The value they typed is ok.  */
  50.       charcode_type kern_char;
  51.       unsigned u;
  52.       font_type *f = (font_type *) client_data;
  53.       char_type *c = FONT_CURRENT_CHAR (*f);
  54.   
  55.       string label_string = ItemGetLabelString (w);
  56.  
  57.       real kern_value = PIXELS_TO_POINTS (atof (value_string), FONT_DPI (*f));
  58.  
  59.       /* Extract the character code out of the item label.  */
  60.       assert (sscanf (label_string, "%u: ", &u) == 1);
  61.       kern_char = u;
  62.   
  63.       /* Update an existing value, or add a new one.  */
  64.       tfm_set_kern (&TFM_KERN (CHAR_TFM_INFO (*c)), kern_char, kern_value);
  65.  
  66.       FONT_MODIFIED (*f) = true;
  67.     }
  68. }
  69.  
  70. /* Add a new kern between the current character and the one specified in
  71.    CALL_DATA.  Give it initial value zero (the user can edit the new
  72.    value as usual once it exists).  */
  73.  
  74. void
  75. add_kern_callback (Widget w, XtPointer client_data, XtPointer call_data)
  76. {
  77.   charcode_type code; 
  78.   string value_string = call_data;
  79.   
  80.   if (XTPARSE_CHARCODE (code, value_string, w))
  81.     {
  82.       font_type *f = (font_type *) client_data;
  83.       char_type *c = FONT_CURRENT_CHAR (*f);
  84.       tfm_char_type tfm_char = CHAR_TFM_INFO (*c);
  85.       list_type kern_list = tfm_char.kern;
  86.       
  87.       if (find_char_in_kern_list (kern_list, code) >= 0)
  88.         x_warning (XtParent (w), "Already in kern list");
  89.       else
  90.         {
  91.           Widget kern_box;
  92.           
  93.           /* Add the kern element to the font.  */
  94.           tfm_set_kern (&TFM_KERN (CHAR_TFM_INFO (*c)), code, 0.0);
  95.           FONT_MODIFIED (*f) = true;
  96.           
  97.           /* Make the new widget.  */
  98.           kern_box = XFIND_WIDGET (XtParent (w), "kern box");
  99.           add_kern_widget (kern_box, f, code, 0.0);
  100.         }
  101.  
  102.       /* Clear the character code we just processed from the Item.  */
  103.       XtVaSetValues (w, XtNvalue, "", NULL, NULL);
  104.     }
  105. }
  106.  
  107.  
  108. /* Create a new Item widget for editing a kern with character CODE in
  109.    font F and value KERN points.  Add the new widget to BOX.  */
  110.  
  111. /* The length here is 1 for a possible sign, 2 for the integer part, the
  112.    decimal point, and 1 for the fractional part.  We're assuming no kern
  113.    will have magnitude > 99.9 pixels.  If this fails, the toolkit will
  114.    give an error about the length not being long enough.  */
  115. #define KERN_VALUE_WIDTH 5
  116.  
  117. void
  118. add_kern_widget (Widget box, font_type *f, charcode_type code, real kern)
  119. {
  120.   char name[MAX_INT_LENGTH + 6];
  121.   char val[MAX_INT_LENGTH + 4];
  122.   string code_string = xmalloc (MAX_INT_LENGTH + 2);
  123.   XtCallbackRec change_kern_callbacks[]
  124.     = SINGLE_CALLBACK (change_kern_callback, f);
  125.   Arg kern_args[]
  126.     = { { XtNlabel,    (XtArgVal) NULL }, /* Assigned below.  */
  127.         { XtNvalue,     (XtArgVal) NULL },
  128.         { XtNcallback,    (XtArgVal) change_kern_callbacks },
  129.         { XtNlength,     (XtArgVal) KERN_VALUE_WIDTH },
  130.       };
  131.  
  132.   sprintf (code_string, "%u: ", code);
  133.   XTASSIGN_ARG (kern_args[0], code_string);
  134.  
  135.   /* We can't use `POINTS_TO_PIXELS' here, since that rounds to the
  136.      nearest whole number of pixels, and we want fractional pixels.  */
  137.   sprintf (val, "%.1f", kern * FONT_DPI (*f) / POINTS_PER_INCH);
  138.   XTASSIGN_ARG (kern_args[1], val);
  139.  
  140.   sprintf (name, "kern %u", code);
  141.   (void) XtCreateManagedWidget (name, itemWidgetClass, box, XTARG (kern_args));
  142. }
  143.  
  144. /* Remove an existing kern between the current character and the one
  145.    specified in CALL_DATA.  */
  146.  
  147. void
  148. remove_kern_callback (Widget w, XtPointer client_data, XtPointer call_data)
  149. {
  150.   charcode_type code; 
  151.   string value_string = call_data;
  152.   
  153.   if (XTPARSE_CHARCODE (code, value_string, w))
  154.     {
  155.       font_type *f = (font_type *) client_data;
  156.       char_type *c = FONT_CURRENT_CHAR (*f);
  157.       list_type *kern_list = &(CHAR_TFM_INFO (*c).kern);
  158.       int loc = find_char_in_kern_list (*kern_list, code);
  159.       
  160.       if (loc < 0)
  161.         x_warning (XtParent (w), "Not in kern list");
  162.       else
  163.         {
  164.           unsigned e;
  165.           char kern_name[7 + MAX_INT_LENGTH];
  166.           
  167.           /* Remove the kern from the list in the font.  */
  168.           free (LIST_ELT (*kern_list, loc));
  169.           for (e = loc + 1; e < LIST_SIZE (*kern_list); e++)
  170.             LIST_ELT (*kern_list, e - 1) = LIST_ELT (*kern_list, e);
  171.           LIST_SIZE (*kern_list)--;
  172.           
  173.           /* Get rid of the widget.  We need the `*' to find the name,
  174.              since the kern items aren't children of the Form, they are
  175.              children of a Box which is a child of the Form.  */
  176.           sprintf (kern_name, "*kern %u", code);
  177.           XtDestroyWidget (XFIND_WIDGET (XtParent (w), kern_name));
  178.  
  179.           /* Clear the character code we just processed from the Item.  */
  180.           XtVaSetValues (w, XtNvalue, "", NULL, NULL);
  181.     
  182.           FONT_MODIFIED (*f) = true;
  183.         }
  184.     }
  185. }
  186.  
  187.  
  188. /* Return the index of the element in KERN_LIST which has code CODE, or
  189.    -1 if no such kern is in KERN_LIST.  */
  190.  
  191. static int
  192. find_char_in_kern_list (list_type kern_list, charcode_type code)
  193. {
  194.   unsigned e;
  195.   
  196.   for (e = 0; e < LIST_SIZE (kern_list); e++)
  197.     {
  198.       tfm_kern_type *k = LIST_ELT (kern_list, e);
  199.       
  200.       if (k->character == code)
  201.         return e;
  202.     }
  203.   
  204.   return -1;
  205. }
  206.  
  207. /* Return the maximum width of a kern item.  Since there may not be any
  208.    kern items extant, we can't just find one and ask for its widget
  209.    width.  Instead, we look up the font resources in the database
  210.    (using the widget TOP as a handle) and then compute the width
  211.    with the X text routines.  */
  212.  
  213. unsigned
  214. find_kern_item_width (Widget top)
  215. {
  216.   XrmValue db_value;
  217.   XFontStruct *f;
  218.   string font_name;
  219.   int kern_width, label_width;
  220.   Dimension label_internal_width;
  221.   string rep_type;
  222.   Display *d = XtDisplay (top);
  223.   XrmDatabase db = XtDatabase (d);
  224.  
  225.   string class = CLASS_NAME ".Box.Item.Label.Font";
  226.   string name = concat (XtName (top), ".kern box.kern 0.item label.font");
  227.   
  228.   /* Find the max width of the label.  The string here is what is used
  229.      in `add_kern_widget', above.  We assume that 0 is as wide as any
  230.      other number.  This assertion and the one below are ok because we
  231.      should never be using the server default font for these items.  To
  232.      be absolutely safe, we should look up XtDefaultFont if this fails,
  233.      but it hardly seems worth it.  */
  234.   assert (XrmGetResource (db, name, class, &rep_type, &db_value));
  235.   
  236.   /* Retrieve the font structure.  */
  237.   font_name = db_value.addr;
  238.   f = XLoadQueryFont (d, font_name);
  239.   
  240.   /* Find the width.  Assume no nulls in TEXT.  */
  241.   label_width = XTextWidth (f, "000: ", 5);
  242.  
  243.   /* Free the memory used.  */
  244.   XFreeFont (d, f);
  245.   free (name);
  246.   
  247.   
  248.   /* Find the max width of the value.  Here we must use the same
  249.      algorithm the Item does for its value subwidget: multiply the
  250.      length of the text by the maximum width from the font bounding box.  */
  251.   class = CLASS_NAME ".Box.Item.Text.Font";
  252.   name = concat (XtName (top), ".kern box.kern 0.item value.font");
  253.   assert (XrmGetResource (db, name, class, &rep_type, &db_value));
  254.   
  255.   /* Retrieve the font structure.  */
  256.   font_name = db_value.addr;
  257.   f = XLoadQueryFont (d, font_name);
  258.   kern_width
  259.     = KERN_VALUE_WIDTH * (f->max_bounds.rbearing - f->min_bounds.lbearing);
  260.   
  261.   /* Free the memory used.  */
  262.   XFreeFont (d, f);
  263.   free (name);
  264.   
  265.   
  266.   /* Last thing: look up the internal width of the label subwidget of
  267.      the Item, so we can add that in.  We assume the margins on the
  268.      value subwidget are zero, and that the borders are zero.  */
  269.   class = CLASS_NAME ".Box.Item.Label.Width";
  270.   name = concat (XtName (top), ".kern box.kern 0.item label.internalWidth");
  271.   label_internal_width
  272.     = XrmGetResource (db, name, class, &rep_type, &db_value)
  273.       ? atoi (db_value.addr)
  274.       : 4; /* The Label widget's default.  */
  275.   free (name);
  276.  
  277.   return label_width + label_internal_width * 2 + kern_width;
  278. }
  279.