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 / commands.c < prev    next >
C/C++ Source or Header  |  1992-06-01  |  15KB  |  455 lines

  1. /* commands.c: the operations we allow.  The routines here are called
  2.    by the toolkit, as ``callbacks'', when certain events happen.
  3.  
  4. Copyright (C) 1992 Free Software Foundation, Inc.
  5.  
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include "config.h"
  21.  
  22. #include "xt-common.h"
  23.  
  24. #include "Bitmap.h"
  25. #include "font.h"
  26. #include "gf.h"
  27. #include "xmessage.h"
  28.  
  29. #include "char.h"
  30. #include "commands.h"
  31. #include "main.h"
  32.  
  33. /* The filename of the bitmap font we output.  (-output-file)  */
  34. string output_name = NULL;
  35.  
  36. /* The names we construct for the output files.  */
  37. static string gf_output_name, tfm_output_name;
  38.  
  39. /* If the `true' output_names are non-null, we are using a temporary
  40.    output file, and should therefore do a copy when the user exits,
  41.    because the input and output files are the same.  */
  42. static string true_gf_output_name = NULL;
  43. static string true_tfm_output_name = NULL;
  44.  
  45.  
  46. static bitmap_type enlarge_bitmap (bitmap_type);
  47.  
  48. /* Exit the program.  We set the callback up to pass the font name as
  49.    the CLIENT_DATA.  */
  50.  
  51. void
  52. exit_command (Widget w, XtPointer client_data, XtPointer call_data)
  53. {
  54.   string font_name = client_data;
  55.   
  56.   close_font (font_name);
  57.  
  58.   if (true_gf_output_name != NULL)
  59.     xrename (gf_output_name, true_gf_output_name);
  60.  
  61.   if (true_tfm_output_name != NULL)
  62.     xrename (tfm_output_name, true_tfm_output_name);
  63.  
  64.   exit (0);
  65. }
  66.  
  67. /* Move to the next character in the font.  CLIENT_DATA is a pointer to
  68.    a `font_type' structure, and CALL_DATA is ignored.  */
  69.  
  70. void
  71. next_command (Widget w, XtPointer client_data, XtPointer call_data)
  72. {
  73.   unsigned this_char;
  74.   char_type *c = NULL;
  75.   font_type *f = (font_type *) client_data;
  76.     
  77.   for (this_char = FONT_CURRENT_CHARCODE (*f) + 1;
  78.        this_char <= MAX_CHARCODE && c == NULL;
  79.        this_char++)
  80.     c = read_char (*f, this_char);
  81.   
  82.   if (c == NULL)
  83.     x_warning (XtParent (w), "You're at the last character");
  84.   else
  85.     show_char (XtParent (w), f, c);
  86. }
  87.  
  88.  
  89. /* Move to the previous character in the font.  The arguments are the
  90.    same as for `next_command'.  */
  91.  
  92. void
  93. prev_command (Widget w, XtPointer client_data, XtPointer call_data)
  94. {
  95.   int this_char;
  96.   char_type *c = NULL;
  97.   font_type *f = (font_type *) client_data;
  98.     
  99.   for (this_char = FONT_CURRENT_CHARCODE (*f) - 1;
  100.        this_char >= 0 && c == NULL;
  101.        this_char--)
  102.     c = read_char (*f, this_char);
  103.   
  104.   if (c == NULL)
  105.     x_warning (XtParent (w), "You're at the first character");
  106.   else
  107.     show_char (XtParent (w), f, c);
  108. }
  109.  
  110.  
  111. /* Go back to the image that is in the font file, killing all changes.
  112.    Since we made a copy of the bitmap before making changes, we free the
  113.    storage that the copy is occupying.  It would be nice if we could
  114.    change the modified status of the font, but since we don't keep a
  115.    record, we don't know whether this character is the only one that has
  116.    changed.  */
  117.  
  118. void
  119. revert_command (Widget w, XtPointer client_data, XtPointer call_data)
  120. {
  121.   char_type *c;
  122.   font_type *f = (font_type *) client_data;
  123.   charcode_type code = FONT_CURRENT_CHARCODE (*f);
  124.   char_type *original = FONT_CHAR (*f, code);
  125.   
  126.   /* Set the pointer in the font structure to null, so `read_char' will
  127.      have to reread the character.  */
  128.   FONT_CHAR (*f, code) = NULL;
  129.   
  130.   /* Reread the character.  */
  131.   c = read_char (*f, code);
  132.   if (c == NULL)
  133.     FATAL2 ("xbfe: Character %d has somehow been deleted from `%s'",
  134.             FONT_CURRENT_CHARCODE (*f), FONT_NAME (*f));
  135.  
  136.   show_char (XtParent (w), f, c);
  137.  
  138.   /* Release the storage the current character is using.  We must do
  139.      this after rereading the character from the font, so that the same
  140.      memory is not used.  If that happens, `bitmap_set_values' thinks
  141.      nothing has changed.  */
  142.   free_bitmap (&BCHAR_BITMAP (*original));
  143.   free (original);
  144. }
  145.  
  146.  
  147. /* This is invoked when the user hits return (well, when the
  148.    `AcceptValue' action is executed) in the Item widget that allows
  149.    changing the current character.  CLIENT_DATA is a pointer to a
  150.    `font_type' structure.  CALL_DATA is the value string in the item
  151.    widget which the user typed; we hope it parses as a character code.  */
  152.  
  153. void
  154. char_change_callback (Widget w, XtPointer client_data, XtPointer call_data)
  155. {
  156.   charcode_type charcode; 
  157.   string value_string = call_data;
  158.   
  159.   if (XTPARSE_CHARCODE (charcode, value_string, w))
  160.     {
  161.       font_type *f = (font_type *) client_data;
  162.       char_type *c = read_char (*f, charcode);
  163.  
  164.       if (c == NULL)
  165.         x_warning (XtParent (w), "No such character");
  166.       else
  167.         show_char (XtParent (w), f, c);
  168.     }
  169. }
  170.  
  171. /* Change the side bearing values.  */
  172.  
  173. /* We allow the user to give just simple decimal constants.  If we see
  174.    something else, give a warning.  */
  175. #define CHECK_DECIMAL(widget, str)                    \
  176.   if (!integer_ok (str))                        \
  177.     {                                    \
  178.       string s = concat3 ("`", str, "': invalid integer");        \
  179.       x_warning (XtParent (widget), s);                    \
  180.       free (s);                                \
  181.       return;                                \
  182.     }
  183.  
  184. /* We have to do some things the same when either of the side bearings
  185.    changes.  We change the character C according to the side-bearing
  186.    change of OFFSET pixels.  Why did I make this a macro?  */
  187. #define COMMON_CHANGE(f, c, offset)                    \
  188.   {                                    \
  189.     char_info_type *char_info = &CHAR_BITMAP_INFO (*c);            \
  190.     real ds = BITMAP_FONT_DESIGN_SIZE (FONT_BITMAP_FONT (FONT_INFO (*f)));\
  191.     real pt_width = fix_to_real (CHAR_TFM_WIDTH (*char_info) * ds);    \
  192.     real pt_offset = PIXELS_TO_POINTS (offset, FONT_DPI (*f));        \
  193.     real new_tfm_width = pt_width + pt_offset;                \
  194.     TFM_WIDTH (CHAR_TFM_INFO (*c)) = new_tfm_width;            \
  195.     CHAR_TFM_WIDTH (*char_info) = real_to_fix (new_tfm_width / ds);    \
  196.     CHAR_SET_WIDTH (*char_info) += offset;                \
  197.     FONT_MODIFIED (*f) = true;                        \
  198.   }
  199.  
  200. void
  201. lsb_change_callback (Widget w, XtPointer client_data, XtPointer call_data)
  202. {
  203.   int new_lsb, old_lsb;
  204.   string value_string = call_data;
  205.   font_type *f = (font_type *) client_data;
  206.   char_type *c = FONT_CURRENT_CHAR (*f);
  207.  
  208.   assert (c != NULL);
  209.   
  210.   CHECK_DECIMAL (w, value_string);
  211.  
  212.   old_lsb = CHAR_LSB (CHAR_BITMAP_INFO (*c));
  213.   new_lsb = atoi (value_string);
  214.   CHAR_MIN_COL (CHAR_BITMAP_INFO (*c)) = new_lsb;
  215.   CHAR_MAX_COL (CHAR_BITMAP_INFO (*c)) += new_lsb - old_lsb;
  216.   
  217.   COMMON_CHANGE (f, c, new_lsb - old_lsb);
  218. }
  219.  
  220.  
  221. void
  222. rsb_change_callback (Widget w, XtPointer client_data, XtPointer call_data)
  223. {
  224.   int new_rsb, old_rsb;
  225.   string value_string = call_data;
  226.   font_type *f = (font_type *) client_data;
  227.   char_type *c = FONT_CURRENT_CHAR (*f);
  228.  
  229.   assert (c != NULL);
  230.   
  231.   CHECK_DECIMAL (w, value_string);
  232.   
  233.   old_rsb = CHAR_RSB (CHAR_BITMAP_INFO (*c));
  234.   new_rsb = atoi (value_string);
  235.  
  236.   COMMON_CHANGE (f, c, new_rsb - old_rsb);
  237. }
  238.  
  239. /* Expand the bitmap by one pixel on all sides.  */
  240.  
  241. void
  242. expand_command (Widget w, XtPointer client_data, XtPointer call_data)
  243. {
  244.   font_type *f = (font_type *) client_data;
  245.   /* We must use `*bitmap' here, since the editable Bitmap is a child of
  246.      the Viewport.  Incidentally, R3's XtNameToWidget won't work here.  */
  247.   Widget bw = XtNameToWidget (XtParent (w), "*bitmap");
  248.   bitmap_type *b = BitmapBits (bw);
  249.   char_type *c = XTALLOC1 (char_type);
  250.   
  251.   /* Copy the current character, so the `*_set_values' commands can
  252.      notice something is changed.  */
  253.   *c = *FONT_CURRENT_CHAR (*f);
  254.  
  255.   /* Do the enlargement.  */
  256.   BCHAR_BITMAP (*c) = enlarge_bitmap (*b);
  257.   
  258.   /* We have to increase the bounding box for the character.  The best
  259.      way to do this is not obvious.  Right now, we arrange things so
  260.      that the origin of the character does not move, i.e., the new row
  261.      at the bottom is below the baseline, and the new column at the left
  262.      is into the side bearing.  Perhaps we should have four separate
  263.      expand commands (or something along those lines).  */
  264.   BCHAR_SET_WIDTH (*c) += 2;
  265.   BCHAR_MIN_COL (*c)--;
  266.   BCHAR_MAX_COL (*c)++;
  267.   BCHAR_MIN_ROW (*c)--;
  268.   BCHAR_MAX_ROW (*c)++;
  269.  
  270.   /* Display the new values.  */
  271.   show_char (XtParent (w), f, c);
  272.  
  273.   /* Free afterwards; see revert_command.  */
  274.   free_bitmap (b);
  275. }
  276.  
  277.  
  278. /* Expand the bitmap B by one pixel on all four sides.  We return a new
  279.    bitmap.  */
  280.  
  281. static bitmap_type
  282. enlarge_bitmap (bitmap_type b)
  283. {
  284.   bitmap_type new;
  285.   dimensions_type new_size;
  286.   unsigned row;
  287.   
  288.   DIMENSIONS_WIDTH (new_size) = BITMAP_WIDTH (b) + 2;
  289.   DIMENSIONS_HEIGHT (new_size) = BITMAP_HEIGHT (b) + 2;
  290.   
  291.   new = new_bitmap (new_size);
  292.   
  293.   /* `new_bitmap' initializes all the pixels to white, so we don't have
  294.      to do anything to the new rows and columns.  */
  295.   for (row = 1; row < DIMENSIONS_HEIGHT (new_size) - 1; row++)
  296.     {
  297.       one_byte *source = BITMAP_ROW (b, row - 1);
  298.       one_byte *target = BITMAP_ROW (new, row) + 1;
  299.       
  300.       memcpy (target, source, BITMAP_WIDTH (b));
  301.     }
  302.   
  303.   return new;
  304. }
  305.  
  306. /* Save the font (if it's been modified).  The CLIENT_DATA is a pointer
  307.    to a `font_type' structure, as defined in `main.h'.  */
  308.  
  309. /* Write C, a `char_info_type', to the output file.  */
  310. #define OUTPUT_CHAR(c)                            \
  311.   do                                    \
  312.     {                                    \
  313.       gf_char_type gf_char;                        \
  314.                                     \
  315.       GF_CHARCODE (gf_char) = this_char;                \
  316.       GF_BITMAP (gf_char) = BCHAR_BITMAP (c);                \
  317.       GF_CHAR_BB (gf_char) = BCHAR_BB (c);                \
  318.       GF_H_ESCAPEMENT (gf_char) = BCHAR_SET_WIDTH (c);            \
  319.       GF_TFM_WIDTH (gf_char) = BCHAR_TFM_WIDTH (c);            \
  320.       gf_put_char (gf_char);                        \
  321.                                           \
  322.       tfm_put_char (CHAR_TFM_INFO (c));                    \
  323.     }                                    \
  324.   while (0)
  325.  
  326.  
  327. /* We put this in the font comment to identify ourselves.  */
  328. #define OUR_PREFIX "Hand edited"
  329.  
  330. void
  331. save_command (Widget w, XtPointer client_data, XtPointer call_data)
  332. {
  333.   string font_comment, our_comment;
  334.   string pl_output_name;
  335.   unsigned this_char;
  336.   font_type *f_ptr = (font_type *) client_data;
  337.   font_type f = *f_ptr;
  338.   bitmap_font_type bitmap_font = FONT_BITMAP_FONT (FONT_INFO (f));
  339.   Widget bw = XtNameToWidget (XtParent (w), "*bitmap");
  340.  
  341.   if (!(FONT_MODIFIED (f) || BitmapModified (bw)))
  342.     {
  343.       x_warning (XtParent (w),
  344.                  "You didn't change the font, so I won't write it out");
  345.       return;
  346.     }
  347.   
  348.   /* The output file is named the same thing as the input file (except
  349.      we always output in GF format), unless the user has specified an
  350.      output name.  */
  351.   if (output_name == NULL)
  352.     output_name = basename (FONT_NAME (f));
  353.  
  354.   gf_output_name = concat4 (output_name, ".", utoa ((unsigned) FONT_DPI (f)),
  355.                             "gf");
  356.   pl_output_name = concat (output_name, ".pl");
  357.   tfm_output_name = concat (output_name, ".tfm");
  358.  
  359.   /* Since the user can go on editing after a save, however, we must
  360.      make sure not to overwrite either of the input files.  If they do
  361.      want to end up overwriting, we use a temporary file for writing.
  362.      Then, when the user exits, we'll copy the temporary back to the
  363.      real file.  */
  364.   if (same_file_p (BITMAP_FONT_FILENAME (bitmap_font), gf_output_name))
  365.     {
  366.       string temp_dir = getenv ("TMPDIR") ? : "/tmp";
  367.       true_gf_output_name = gf_output_name;
  368.       gf_output_name = concat5 (temp_dir, "/", itoa (getpid ()),
  369.                                 basename (output_name), "gf"); 
  370.     }
  371.   if (same_file_p (FONT_TFM_FILENAME (FONT_INFO (f)), tfm_output_name))
  372.     {
  373.       string temp_dir = getenv ("TMPDIR") ? : "/tmp";
  374.       true_tfm_output_name = tfm_output_name;
  375.       tfm_output_name = concat4 (temp_dir, "/", itoa (getpid ()), ".tfm");
  376.       pl_output_name = concat4 (temp_dir, "/", itoa (getpid ()), ".pl");
  377.     }
  378.  
  379.   /* Open the output files we will write to.  */
  380.   if (!gf_open_output_file (gf_output_name))
  381.     FATAL_PERROR (gf_output_name);
  382.   if (!tfm_open_pl_output_file (pl_output_name))
  383.     FATAL_PERROR (pl_output_name);
  384.     
  385.   /* Don't keep tacking on our prefix to the beginning of the comment;
  386.      instead, replace it if it's already there.  Also, don't bother to
  387.      put the day of the week in the comment.  */
  388.   our_comment = concat3 (OUR_PREFIX " ", now () + 4, " from ");
  389.   font_comment = FONT_COMMENT (FONT_INFO (f));
  390.   if (strncmp (font_comment, OUR_PREFIX, strlen (OUR_PREFIX)) == 0)
  391.     font_comment += strlen (our_comment);
  392.  
  393.   /* Output the stuff at the beginning.  */
  394.   gf_put_preamble (concat (our_comment, font_comment));
  395.   tfm_put_global_info (FONT_TFM_FONT (FONT_INFO (f)));
  396.  
  397.   for (this_char = 0; this_char <= MAX_CHARCODE; this_char++)
  398.     {
  399.       char_type *c = FONT_CHAR (f, this_char);
  400.       
  401.       /* First see if we've read this character, i.e., if the user has
  402.          edited (well, at least selected) it.  */
  403.       if (c != NULL)
  404.         OUTPUT_CHAR (*c);
  405.       else
  406.         { 
  407.           tfm_char_type *tfm_char;
  408.           
  409.           /* The character hasn't been seen, so now we need to see if
  410.              it's in the font.  If it is, though, there is no point in
  411.              doing all the work of decoding and then re-encoding the
  412.              bitmap, so we just read the raw bytes.  */
  413.           raw_char_type *c = get_raw_char (FONT_NAME (f), this_char);
  414.           if (c != NULL && RAW_CHAR_BITMAP_FORMAT (*c) == gf_format)
  415.             {
  416.               /* We found it in the font, although the user hasn't seen
  417.                  it yet.  We just write out the same bytes that were
  418.                  already present in the font file.  */
  419.               gf_put_raw_char (*c);
  420.               free_raw_char (c);
  421.               
  422.               /* Also output the TFM character, just as we read it.  */
  423.               tfm_char = tfm_get_char (this_char);
  424.               if (tfm_char != NULL)
  425.                 tfm_put_char (*tfm_char);
  426.             }
  427.           else
  428.             { /* It's not available as a raw character in the right
  429.                  format.  We still have to test if it's available at all.  */
  430.               char_type *c = read_char (f, this_char);
  431.               if (c != NULL)
  432.                 {
  433.                   OUTPUT_CHAR (*c);
  434.                   
  435.                   /* We might as well save the character away, to avoid
  436.                      reconstructing the bitmap if they either visit the
  437.                      character or just save again.  */
  438.                   FONT_CHAR (f, this_char) = c;
  439.                 }
  440.             }
  441.         }
  442.     }
  443.  
  444.   gf_put_postamble (real_to_fix (FONT_DESIGN_SIZE (FONT_INFO (f))),
  445.                     FONT_DPI (f), FONT_DPI (f));
  446.  
  447.   /* Make the TFM file from the PL file.  */
  448.   tfm_convert_pl (NULL, false);
  449.   
  450.   /* Close the output files, since we will write them again from scratch
  451.      next time.  */
  452.   gf_close_output_file ();
  453.   tfm_close_pl_output_file ();
  454. }
  455.