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 / main.c < prev    next >
C/C++ Source or Header  |  1992-08-23  |  18KB  |  492 lines

  1. /* xbfe -- a bitmap font editor for X11.
  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 "xt-common.h"
  22. #include <X11/Xaw/Box.h>
  23. #include <X11/Xaw/Command.h>
  24. #include <X11/Xaw/Form.h>
  25. #include <X11/Xaw/Viewport.h>
  26.  
  27. #include "Bitmap.h"
  28. #include "cmdline.h"
  29. #include "font.h"
  30. #include "getopt.h"
  31. #include "Item.h"
  32. #include "rand.h"
  33.  
  34. #include "char.h"
  35. #include "commands.h"
  36. #include "kern.h"
  37. #include "main.h"
  38.  
  39.  
  40. /* The resolution of the font we will read, in pixels per inch.  We
  41.    don't deal with nonsquare pixels.  (-dpi)  */
  42. string dpi = "300";
  43.  
  44. /* The representation of the font we're working on.  We depend on the
  45.    character pointers all being initialized to NULL.  */
  46. static font_type the_font;
  47.  
  48.  
  49. static void create_widgets (Widget, char_type *);
  50. static string read_command_line (int, string[]);
  51. static Boolean update_position (XtPointer);
  52.  
  53. int
  54. main (int argc, string argv[])
  55. {
  56.   unsigned this_char;
  57.   char_type *c;
  58.   /* We parse more options with getopt in `read_command_line', below.  */
  59.   XrmOptionDescRec x_options[]
  60.     = { { "-expansion", "*expansion", XrmoptionSepArg, NULL },
  61.         { "--expansion", "*expansion", XrmoptionSepArg, NULL },
  62.       };
  63.   Widget top_level = XtInitialize (NULL, CLASS_NAME, XTARG (x_options),
  64.                                    &argc, argv);
  65.  
  66.   FONT_NAME (the_font) = read_command_line (argc, argv);
  67.   FONT_DPI (the_font) = atof (dpi);
  68.  
  69.   /* Find the font before creating any widgets, so if the font isn't
  70.      found, we don't waste time.  xx need to only get_bitmap_font if
  71.      there is no tfm file */
  72.   FONT_INFO (the_font) = get_font (FONT_NAME (the_font), atou (dpi));
  73.   
  74.   /* Find the first character in the font to use for the current
  75.      character, if the current character is set to something besides
  76.      zero, or if the current character doesn't exist.  */
  77.   c = read_char (the_font, FONT_CURRENT_CHARCODE (the_font));
  78.  
  79.   if (c == NULL)
  80.     {
  81.       for (this_char = 0; this_char <= MAX_CHARCODE && c == NULL; this_char++)
  82.         c = read_char (the_font, this_char);
  83.  
  84.       if (c == NULL)
  85.         FATAL1 ("xbfe: No characters in the font `%s'", FONT_NAME (the_font));
  86.  
  87.       FONT_CURRENT_CHARCODE (the_font) = this_char - 1;
  88.     }
  89.  
  90.   FONT_CURRENT_CHAR (the_font) = c;
  91.  
  92.   /* Make a copy of the first bitmap so the original isn't changed.  */
  93.   BCHAR_BITMAP (*c) = copy_bitmap (BCHAR_BITMAP (*c));
  94.  
  95.   /* OK, we have something to edit.  Initialize the other fields of the
  96.      font structure.  */
  97.   FONT_MODIFIED (the_font) = false;
  98.   FONT_DPI (the_font) = atof (dpi);
  99.   
  100.   /* Don't keep a checksum when and if we write the font.  */
  101.   TFM_CHECKSUM (FONT_TFM_FONT (FONT_INFO (the_font))) = 0;
  102.   
  103.   create_widgets (top_level, FONT_CURRENT_CHAR (the_font));
  104.   
  105.   XtRealizeWidget (top_level);
  106.  
  107.   XtMainLoop ();
  108.   
  109.   return 0;
  110. }
  111.  
  112. /* Create the widget hierarchy underneath TOP.  The bitmap to be
  113.    initially displayed is INITIAL_BITMAP.  We also use the global
  114.    `the_font', and set the widgets in that structure.  */
  115.  
  116. /* Will we ever need side bearings larger than 999 or -99 pixels?  */
  117. #define MAX_SB_LENGTH 3
  118.  
  119. static void
  120. create_widgets (Widget top, char_type *initial_char)
  121. {
  122.   Widget form_widget;
  123.  
  124.   /* The basic commands for the user.  These are strung along the top of
  125.      the window, in the order given.  */
  126.   Widget widget_to_the_left, widget_above;
  127.   DECLARE_BUTTON (prev, "Prev", &the_font);
  128.   DECLARE_BUTTON (next, "Next", &the_font);
  129.   DECLARE_BUTTON (revert, "Revert", &the_font);
  130.   DECLARE_BUTTON (expand, "Expand", &the_font);
  131.   DECLARE_BUTTON (save, "Save", &the_font);
  132.   DECLARE_BUTTON (exit, "Exit", FONT_NAME (the_font));
  133.  
  134. #if 0
  135.   /* Tell them the resolution, in pixels per point.  It might be nice to
  136.      be able to show dimensions in either points or pixels, but this
  137.      suffices for us.  */
  138.   string ppp_string = xmalloc (16); /* See the sprintf below.  */
  139.   Arg ppp_args[]
  140.     = { { XtNfromHoriz,    NULL }, /* We assign to this below.  */
  141.         { XtNlabel,    (XtArgVal) ppp_string },
  142.       };
  143.   Widget ppp_widget;
  144. #endif  /* 0 */
  145.  
  146.   /* An Item widget for changing the character randomly.  */
  147.   static XtCallbackRec char_change_callbacks[]
  148.     = SINGLE_CALLBACK (char_change_callback, &the_font);
  149.   
  150.   Arg item_args[]
  151.     = { { XtNfromHoriz,    (XtArgVal) NULL }, /* We assign to this below.  */
  152.         { XtNvalue,    (XtArgVal) NULL }, /* And this.  */
  153.         { XtNcallback,    (XtArgVal) char_change_callbacks },
  154.         { XtNlabel,    (XtArgVal) "Char: " },
  155.         { XtNlength,    4 },    /* Longest valid code, e.g., `0xff'.  */
  156.       };
  157.   Widget item_widget;
  158.  
  159.   Arg position_args[]
  160.     = { { XtNfromHoriz,    (XtArgVal) NULL }, /* We assign to this below.  */
  161.       };
  162.   Widget position_widget;
  163.   Widget *update_position_data;
  164.     
  165.   /* An item widget for changing the left side bearing.  */
  166.   static XtCallbackRec lsb_callbacks[]
  167.     = SINGLE_CALLBACK (lsb_change_callback, &the_font);
  168.   Arg lsb_args[]
  169.     = { { XtNfromVert,    (XtArgVal) NULL }, /* We assign to this below.  */
  170.         { XtNcallback,    (XtArgVal) lsb_callbacks },
  171.         { XtNlabel,    (XtArgVal) "lsb: " },
  172.         { XtNlength,    MAX_SB_LENGTH },
  173.       };
  174.   Widget lsb_widget;
  175.  
  176.   /* And one for changing the rsb.  */
  177.   static XtCallbackRec rsb_callbacks[]
  178.     = SINGLE_CALLBACK (rsb_change_callback, &the_font);
  179.   Arg rsb_args[]
  180.     = { { XtNfromHoriz,    (XtArgVal) NULL }, /* We assign to this below.  */
  181.         { XtNfromVert,    (XtArgVal) NULL }, /* And this.  */
  182.         { XtNcallback,    (XtArgVal) rsb_callbacks },
  183.         { XtNlabel,    (XtArgVal) "rsb: " },
  184.         { XtNlength,    MAX_SB_LENGTH },
  185.       };
  186.   Widget rsb_widget;
  187.  
  188.   /* Widgets to manipulate the kerning table.  */
  189.   static XtCallbackRec add_kern_callbacks[]
  190.     = SINGLE_CALLBACK (add_kern_callback, &the_font);
  191.   Arg add_kern_args[]
  192.     = { { XtNfromHoriz, (XtArgVal) NULL }, /* Assigned below.  */
  193.         { XtNfromVert,    (XtArgVal) NULL },    /* Assigned below.  */
  194.         { XtNlength,    4 },    /* Longest valid character code.  */
  195.         { XtNlabel,    (XtArgVal) "Add kern: "},
  196.         { XtNcallback,    (XtArgVal) add_kern_callbacks },
  197.       };
  198.   Widget add_kern_widget;
  199.  
  200.   static XtCallbackRec remove_kern_callbacks[]
  201.     = SINGLE_CALLBACK (remove_kern_callback, &the_font);
  202.   Arg remove_kern_args[]
  203.     = { { XtNfromHoriz, (XtArgVal) NULL }, /* Assigned below.  */
  204.         { XtNfromVert,     (XtArgVal) NULL },    /* Assigned below.  */
  205.         { XtNlength,    4 },    /* Longest valid character code.  */
  206.         { XtNlabel,    (XtArgVal) "Del kern: "},
  207.         { XtNcallback,    (XtArgVal) remove_kern_callbacks },
  208.       };
  209.   Widget remove_kern_widget;
  210.  
  211.   /* One Bitmap widget, with no expansion, displays the edited bitmap at
  212.      its true size.  */
  213.   Arg true_bitmap_args[]
  214.     = { { XtNfromVert,    (XtArgVal) NULL }, /* We assign to this below.  */
  215.         { XtNbits, (XtArgVal) &BCHAR_BITMAP (*initial_char) },
  216.         { XtNexpansion,    1 },
  217.       };
  218.   Widget true_bitmap_widget;
  219.  
  220.   Arg kern_box_args[]
  221.     = { { XtNfromVert,    (XtArgVal) NULL },    /* Assigned below.  */
  222.       };
  223.   Widget kern_box_widget;
  224.  
  225.   /* The viewport widget will contain the editable bitmap.  It does the
  226.      scrolling of the (potentially big) bitmap for us.  */
  227.   Arg viewport_args[]
  228.     = { { XtNfromVert,        (XtArgVal) NULL },  /* Assigned below.  */
  229.         { XtNhorizDistance,    (XtArgVal) NULL },
  230.       };
  231.   Widget viewport_widget;
  232.   
  233.   /* The bitmap widget handles the actual pixel pushing.  */
  234.   Arg bitmap_args[]
  235.     = { { XtNshadow,    (XtArgVal) NULL }, /* Assigned below.  */
  236.         { XtNbits,    (XtArgVal) &BCHAR_BITMAP (*initial_char) },
  237.       };
  238.   Widget bitmap_widget;
  239.  
  240.  
  241.   /* We specify the arguments for the Form in the defaults file.  */
  242.   form_widget = XtCreateManagedWidget ("form", formWidgetClass, top, NULL, 0);
  243.  
  244.   prev_widget = XtCreateManagedWidget ("prev", commandWidgetClass, form_widget,
  245.                                        prev_args, XtNumber (prev_args));
  246.  
  247.   widget_to_the_left = prev_widget;
  248.   DEFINE_BUTTON (next, form_widget);
  249.   DEFINE_BUTTON (revert, form_widget);
  250.   DEFINE_BUTTON (expand, form_widget);
  251.   DEFINE_BUTTON (save, form_widget);
  252.   DEFINE_BUTTON (exit, form_widget);
  253.  
  254. #if 0
  255.   /* Don't bother with this anymore; there's not enough space on screen.  */
  256.   XTASSIGN_ARG (ppp_args[0], exit_widget);
  257.   sprintf (ppp_string, "px/pt=%.2f", FONT_DPI (the_font) / POINTS_PER_INCH);
  258.   ppp_widget = XtCreateManagedWidget ("ppp", labelWidgetClass,
  259.                                       form_widget, XTARG (ppp_args));
  260.   widget_to_the_left = ppp_widget;
  261. #endif
  262.  
  263.   XTASSIGN_ARG (item_args[0], widget_to_the_left);
  264.   XTASSIGN_ARG (item_args[1], utoa (FONT_CURRENT_CHARCODE (the_font)));
  265.   item_widget
  266.     = XtCreateManagedWidget ("current character item", itemWidgetClass,
  267.                              form_widget, XTARG (item_args)); 
  268.   widget_to_the_left = item_widget;
  269.  
  270.   XTASSIGN_ARG (position_args[0], item_widget);
  271.   position_widget = XtCreateManagedWidget ("position", labelWidgetClass,
  272.                                            form_widget, XTARG (position_args));
  273.  
  274.   /* So much for the top row.  The next row contains the left side
  275.      bearing and right side bearing items, and add/remove kern items.  */
  276.   widget_above = prev_widget; /* Any in the top row would do.  */
  277.  
  278.   XTASSIGN_ARG (lsb_args[0], widget_above);
  279.   lsb_widget = XtCreateManagedWidget ("lsb item", itemWidgetClass,
  280.                                       form_widget, XTARG (lsb_args));
  281.  
  282.   XTASSIGN_ARG (rsb_args[0], lsb_widget);
  283.   XTASSIGN_ARG (rsb_args[1], widget_above);
  284.   rsb_widget = XtCreateManagedWidget ("rsb item", itemWidgetClass,
  285.                                       form_widget, XTARG (rsb_args));
  286.   
  287.   XTASSIGN_ARG (add_kern_args[0], rsb_widget);
  288.   XTASSIGN_ARG (add_kern_args[1], widget_above);
  289.   add_kern_widget = XtCreateManagedWidget ("+kern", itemWidgetClass,
  290.                                           form_widget, XTARG (add_kern_args)); 
  291.  
  292.   XTASSIGN_ARG (remove_kern_args[0], add_kern_widget);
  293.   XTASSIGN_ARG (remove_kern_args[1], widget_above);
  294.   remove_kern_widget = XtCreateManagedWidget ("-kern", itemWidgetClass,
  295.                                         form_widget, XTARG (remove_kern_args));
  296.  
  297.   /* The next row is the true-size bitmap.  */
  298.   widget_above = lsb_widget;
  299.   
  300.   XTASSIGN_ARG (true_bitmap_args[0], widget_above);
  301.   true_bitmap_widget = XtCreateManagedWidget ("true bitmap", bitmapWidgetClass,
  302.                                         form_widget, XTARG (true_bitmap_args));
  303.  
  304.   /* The next row is the kern box.  */
  305.   XTASSIGN_ARG (kern_box_args[0], true_bitmap_widget);
  306.   kern_box_widget = XtCreateManagedWidget ("kern box", boxWidgetClass,
  307.                                            form_widget, XTARG (kern_box_args));
  308.  
  309.   /* The Viewport holds the editable bitmap. We don't want it to overlap
  310.      with any of the other windows, and yet we want to have as much
  311.      screen space as possible.  So we put it below the previous row with
  312.      the lsb_widget, even though we've also put in the kern box and true
  313.      bitmap since then.  To ensure that it doesn't overlap with those
  314.      two horizontally, we compute the width of a kern item, and the
  315.      width of 1em, and make that the distance from the left edge.  This
  316.      fails if a character's width > 1em > width (kern item), but that is
  317.      an unlikely cirumstance.  We don't find the actual width of the
  318.      widest character in the font, since then we would (perhaps) have to
  319.      read all its characters.  */
  320.   XTASSIGN_ARG (viewport_args[0], lsb_widget);
  321.   {
  322.     unsigned box_border;
  323.     /* Compute an em in pixels.  */
  324.     tfm_global_info_type tfm_info = FONT_TFM_FONT (FONT_INFO (the_font));
  325.     real em_points = TFM_SAFE_FONTDIMEN (tfm_info, TFM_QUAD_PARAMETER,
  326.                                          TFM_DESIGN_SIZE (tfm_info));
  327.     unsigned em_pixels = POINTS_TO_PIXELS (em_points, FONT_DPI (the_font));
  328.     
  329.     /* Find the maximum width of a kern item.  */
  330.     unsigned kern_item_width = find_kern_item_width (top);
  331.     
  332.     /* Use the max, plus the border width of the kern box.  We assume
  333.        the border width of the form and other widgets is zero.  */
  334.     unsigned offset = MAX (em_pixels, kern_item_width); 
  335.     
  336.     XtVaGetValues (kern_box_widget, XtNborderWidth, &box_border, NULL, NULL);
  337.     offset += box_border * 2;
  338.     
  339.     XTASSIGN_ARG (viewport_args[1], offset);
  340.   }
  341.   viewport_widget = XtCreateManagedWidget ("viewport", viewportWidgetClass,
  342.                                            form_widget, XTARG (viewport_args));
  343.  
  344.   /* The Viewport will manage the editable Bitmap.  We want the
  345.      `true_bitmap' to be updated when the Bitmap is edited, so assign to
  346.      the shadow resource.  */
  347.   XTASSIGN_ARG (bitmap_args[0], true_bitmap_widget);
  348.   bitmap_widget = XtCreateManagedWidget ("bitmap", bitmapWidgetClass,
  349.                                          viewport_widget, XTARG (bitmap_args));
  350.  
  351.   /* We want to show the coordinates of the pointer in the bitmap
  352.      widget whenever we have some spare time.  We may as well pass the
  353.      widgets to the procedure.  */
  354.   update_position_data = xmalloc (sizeof (Widget) * 2);
  355.   update_position_data[0] = position_widget;
  356.   update_position_data[1] = bitmap_widget;
  357.   (void) XtAddWorkProc (update_position, update_position_data);
  358.   
  359.   show_char (form_widget, &the_font, initial_char);
  360. }
  361.  
  362. /* This routine is called at idle times.  We want to display the
  363.    coordinates of the pointer, if it's in the bitmap widget.  We are
  364.    passed in CLIENT_DATA an array of two Widget pointers: the first is
  365.    the label we are supposed to display the information; the second is
  366.    the bitmap widget we are supposed to find the coordinates relative
  367.    to.  Since it's more important to not consume cycles during periods
  368.    of work than to provide an accurate display at all times, we do
  369.    nothing at all on some percentage of calls.  */
  370.  
  371. static Boolean
  372. update_position (XtPointer client_data)
  373. {
  374.   static char last_str[MAX_INT_LENGTH * 2 + 2] = "";
  375.   char str[sizeof (last_str)];
  376.   unsigned mask;
  377.   Window root_window, child_window;
  378.   int root_x, root_y, win_x, win_y;
  379.   Widget *widgets = (Widget *) client_data;
  380.   Widget bw = widgets[1];
  381.   real test_value = (real) k_rand ();
  382.   
  383.   if (test_value / RAND_MAX < .75)
  384.     return False;
  385.     
  386.   if (XQueryPointer (XtDisplay (bw), XtWindow (bw), &root_window,
  387.                      &child_window, &root_x, &root_y, &win_x, &win_y, &mask))
  388.     { /* They're on the same screen.  Now see if the coordinate is
  389.           actually within the bitmap.  */
  390.       unsigned expansion = BitmapExpansion (bw);
  391.       int row = win_y / expansion;
  392.       int col = win_x / expansion;
  393.       bitmap_type *bitmap = BitmapBits (bw);
  394.       
  395.       if (row < 0 || row >= BITMAP_HEIGHT (*bitmap)
  396.           || col < 0 || col >= BITMAP_WIDTH (*bitmap))
  397.         str[0] = 0; 
  398.       else
  399.         sprintf (str, "%u,%u", col, row);
  400.     }
  401.   else
  402.     str[0] = 0;
  403.   
  404.   if (!STREQ (str, last_str))
  405.     {
  406.       Widget lw = widgets[0];
  407.       XtVaSetValues (lw, XtNlabel, str, NULL, NULL);
  408.       strcpy (last_str, str);
  409.     }
  410.   
  411.   /* We never want to be deleted from the work queue.  */
  412.   return False;
  413. }
  414.  
  415. /* Reading the options (besides the standard Xt options and our own X
  416.    options, which have already been removed).  The arguments recognized
  417.    below do not have equivalents in X's resource database, nor should
  418.    they, particularly.  So we don't want to give them to X to parse.  */
  419.  
  420. /* This is defined in version.c.  */
  421. extern string version_string;
  422.  
  423. #define USAGE "Options:
  424. <font_name> should be a filename, possibly with a resolution, e.g.,
  425.   `cmr10' or `cmr10.300'.\n"                        \
  426.   GETOPT_USAGE                                 \
  427. "  The standard X toolkit options are also accepted.  The class name is `XBfe'.
  428. dpi <unsigned>: use this resolution; default is 300.
  429. expansion <unsigned>: each pixel in the bitmap will be this many pixels
  430.   square on the display; default is 12.  You can't use `=' here to
  431.   separate the option name and value.  You can set this value by setting
  432.   a resource `expansion' in your .Xdefaults file.
  433. initial-char <char>: start up displaying the character <char>; default is
  434.   the character in the font with the smallest code.
  435. help: print this message.
  436. output-file <filename>: use <filename> as the output file; default is
  437.   `<font_name>.<dpi>gf' and `<font_name>.tfm'.
  438. version: print the version number of this program.
  439. "
  440.  
  441. static string
  442. read_command_line (int argc, string argv[])
  443. {
  444.   int g;   /* `getopt' return code.  */
  445.   int option_index;
  446.   boolean explicit_dpi = false;
  447.   boolean printed_version = false;
  448.   struct option long_options[]
  449.     = { { "dpi",            1, (int *) &explicit_dpi, 1 },
  450.         { "initial-char",        1, 0, 0 },
  451.         { "help",                       0, 0, 0 },
  452.         { "output-file",        1, 0, 0 },
  453.         { "version",            0, (int *) &printed_version, 1 },
  454.         { 0, 0, 0, 0 } };
  455.   
  456.   while (true)
  457.     {
  458.       g = getopt_long_only (argc, argv, "", long_options, &option_index);
  459.       
  460.       if (g == EOF)
  461.         break;
  462.  
  463.       if (g == '?')
  464.         continue;  /* Unknown option.  */
  465.   
  466.       assert (g == 0); /* We have no short option names.  */
  467.   
  468.       if (ARGUMENT_IS ("dpi"))
  469.         dpi = optarg;
  470.       
  471.       else if (ARGUMENT_IS ("initial-char"))
  472.         FONT_CURRENT_CHARCODE (the_font) = xparse_charcode (optarg);
  473.         
  474.       else if (ARGUMENT_IS ("help"))
  475.         {
  476.           fprintf (stderr, "Usage: %s [options] <font_name>.\n", argv[0]);
  477.           fprintf (stderr, USAGE);
  478.           exit (0);
  479.         }
  480.  
  481.       else if (ARGUMENT_IS ("output-file"))
  482.         output_name = optarg;
  483.         
  484.       else if (ARGUMENT_IS ("version"))
  485.         printf ("%s.\n", version_string);
  486.       
  487.       /* Else it was just a flag; getopt has already done the assignment.  */
  488.     }
  489.  
  490.   FINISH_COMMAND_LINE ();
  491. }
  492.