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 >
Wrap
C/C++ Source or Header
|
1992-08-23
|
18KB
|
492 lines
/* xbfe -- a bitmap font editor for X11.
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 "xt-common.h"
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Viewport.h>
#include "Bitmap.h"
#include "cmdline.h"
#include "font.h"
#include "getopt.h"
#include "Item.h"
#include "rand.h"
#include "char.h"
#include "commands.h"
#include "kern.h"
#include "main.h"
/* The resolution of the font we will read, in pixels per inch. We
don't deal with nonsquare pixels. (-dpi) */
string dpi = "300";
/* The representation of the font we're working on. We depend on the
character pointers all being initialized to NULL. */
static font_type the_font;
static void create_widgets (Widget, char_type *);
static string read_command_line (int, string[]);
static Boolean update_position (XtPointer);
int
main (int argc, string argv[])
{
unsigned this_char;
char_type *c;
/* We parse more options with getopt in `read_command_line', below. */
XrmOptionDescRec x_options[]
= { { "-expansion", "*expansion", XrmoptionSepArg, NULL },
{ "--expansion", "*expansion", XrmoptionSepArg, NULL },
};
Widget top_level = XtInitialize (NULL, CLASS_NAME, XTARG (x_options),
&argc, argv);
FONT_NAME (the_font) = read_command_line (argc, argv);
FONT_DPI (the_font) = atof (dpi);
/* Find the font before creating any widgets, so if the font isn't
found, we don't waste time. xx need to only get_bitmap_font if
there is no tfm file */
FONT_INFO (the_font) = get_font (FONT_NAME (the_font), atou (dpi));
/* Find the first character in the font to use for the current
character, if the current character is set to something besides
zero, or if the current character doesn't exist. */
c = read_char (the_font, FONT_CURRENT_CHARCODE (the_font));
if (c == NULL)
{
for (this_char = 0; this_char <= MAX_CHARCODE && c == NULL; this_char++)
c = read_char (the_font, this_char);
if (c == NULL)
FATAL1 ("xbfe: No characters in the font `%s'", FONT_NAME (the_font));
FONT_CURRENT_CHARCODE (the_font) = this_char - 1;
}
FONT_CURRENT_CHAR (the_font) = c;
/* Make a copy of the first bitmap so the original isn't changed. */
BCHAR_BITMAP (*c) = copy_bitmap (BCHAR_BITMAP (*c));
/* OK, we have something to edit. Initialize the other fields of the
font structure. */
FONT_MODIFIED (the_font) = false;
FONT_DPI (the_font) = atof (dpi);
/* Don't keep a checksum when and if we write the font. */
TFM_CHECKSUM (FONT_TFM_FONT (FONT_INFO (the_font))) = 0;
create_widgets (top_level, FONT_CURRENT_CHAR (the_font));
XtRealizeWidget (top_level);
XtMainLoop ();
return 0;
}
/* Create the widget hierarchy underneath TOP. The bitmap to be
initially displayed is INITIAL_BITMAP. We also use the global
`the_font', and set the widgets in that structure. */
/* Will we ever need side bearings larger than 999 or -99 pixels? */
#define MAX_SB_LENGTH 3
static void
create_widgets (Widget top, char_type *initial_char)
{
Widget form_widget;
/* The basic commands for the user. These are strung along the top of
the window, in the order given. */
Widget widget_to_the_left, widget_above;
DECLARE_BUTTON (prev, "Prev", &the_font);
DECLARE_BUTTON (next, "Next", &the_font);
DECLARE_BUTTON (revert, "Revert", &the_font);
DECLARE_BUTTON (expand, "Expand", &the_font);
DECLARE_BUTTON (save, "Save", &the_font);
DECLARE_BUTTON (exit, "Exit", FONT_NAME (the_font));
#if 0
/* Tell them the resolution, in pixels per point. It might be nice to
be able to show dimensions in either points or pixels, but this
suffices for us. */
string ppp_string = xmalloc (16); /* See the sprintf below. */
Arg ppp_args[]
= { { XtNfromHoriz, NULL }, /* We assign to this below. */
{ XtNlabel, (XtArgVal) ppp_string },
};
Widget ppp_widget;
#endif /* 0 */
/* An Item widget for changing the character randomly. */
static XtCallbackRec char_change_callbacks[]
= SINGLE_CALLBACK (char_change_callback, &the_font);
Arg item_args[]
= { { XtNfromHoriz, (XtArgVal) NULL }, /* We assign to this below. */
{ XtNvalue, (XtArgVal) NULL }, /* And this. */
{ XtNcallback, (XtArgVal) char_change_callbacks },
{ XtNlabel, (XtArgVal) "Char: " },
{ XtNlength, 4 }, /* Longest valid code, e.g., `0xff'. */
};
Widget item_widget;
Arg position_args[]
= { { XtNfromHoriz, (XtArgVal) NULL }, /* We assign to this below. */
};
Widget position_widget;
Widget *update_position_data;
/* An item widget for changing the left side bearing. */
static XtCallbackRec lsb_callbacks[]
= SINGLE_CALLBACK (lsb_change_callback, &the_font);
Arg lsb_args[]
= { { XtNfromVert, (XtArgVal) NULL }, /* We assign to this below. */
{ XtNcallback, (XtArgVal) lsb_callbacks },
{ XtNlabel, (XtArgVal) "lsb: " },
{ XtNlength, MAX_SB_LENGTH },
};
Widget lsb_widget;
/* And one for changing the rsb. */
static XtCallbackRec rsb_callbacks[]
= SINGLE_CALLBACK (rsb_change_callback, &the_font);
Arg rsb_args[]
= { { XtNfromHoriz, (XtArgVal) NULL }, /* We assign to this below. */
{ XtNfromVert, (XtArgVal) NULL }, /* And this. */
{ XtNcallback, (XtArgVal) rsb_callbacks },
{ XtNlabel, (XtArgVal) "rsb: " },
{ XtNlength, MAX_SB_LENGTH },
};
Widget rsb_widget;
/* Widgets to manipulate the kerning table. */
static XtCallbackRec add_kern_callbacks[]
= SINGLE_CALLBACK (add_kern_callback, &the_font);
Arg add_kern_args[]
= { { XtNfromHoriz, (XtArgVal) NULL }, /* Assigned below. */
{ XtNfromVert, (XtArgVal) NULL }, /* Assigned below. */
{ XtNlength, 4 }, /* Longest valid character code. */
{ XtNlabel, (XtArgVal) "Add kern: "},
{ XtNcallback, (XtArgVal) add_kern_callbacks },
};
Widget add_kern_widget;
static XtCallbackRec remove_kern_callbacks[]
= SINGLE_CALLBACK (remove_kern_callback, &the_font);
Arg remove_kern_args[]
= { { XtNfromHoriz, (XtArgVal) NULL }, /* Assigned below. */
{ XtNfromVert, (XtArgVal) NULL }, /* Assigned below. */
{ XtNlength, 4 }, /* Longest valid character code. */
{ XtNlabel, (XtArgVal) "Del kern: "},
{ XtNcallback, (XtArgVal) remove_kern_callbacks },
};
Widget remove_kern_widget;
/* One Bitmap widget, with no expansion, displays the edited bitmap at
its true size. */
Arg true_bitmap_args[]
= { { XtNfromVert, (XtArgVal) NULL }, /* We assign to this below. */
{ XtNbits, (XtArgVal) &BCHAR_BITMAP (*initial_char) },
{ XtNexpansion, 1 },
};
Widget true_bitmap_widget;
Arg kern_box_args[]
= { { XtNfromVert, (XtArgVal) NULL }, /* Assigned below. */
};
Widget kern_box_widget;
/* The viewport widget will contain the editable bitmap. It does the
scrolling of the (potentially big) bitmap for us. */
Arg viewport_args[]
= { { XtNfromVert, (XtArgVal) NULL }, /* Assigned below. */
{ XtNhorizDistance, (XtArgVal) NULL },
};
Widget viewport_widget;
/* The bitmap widget handles the actual pixel pushing. */
Arg bitmap_args[]
= { { XtNshadow, (XtArgVal) NULL }, /* Assigned below. */
{ XtNbits, (XtArgVal) &BCHAR_BITMAP (*initial_char) },
};
Widget bitmap_widget;
/* We specify the arguments for the Form in the defaults file. */
form_widget = XtCreateManagedWidget ("form", formWidgetClass, top, NULL, 0);
prev_widget = XtCreateManagedWidget ("prev", commandWidgetClass, form_widget,
prev_args, XtNumber (prev_args));
widget_to_the_left = prev_widget;
DEFINE_BUTTON (next, form_widget);
DEFINE_BUTTON (revert, form_widget);
DEFINE_BUTTON (expand, form_widget);
DEFINE_BUTTON (save, form_widget);
DEFINE_BUTTON (exit, form_widget);
#if 0
/* Don't bother with this anymore; there's not enough space on screen. */
XTASSIGN_ARG (ppp_args[0], exit_widget);
sprintf (ppp_string, "px/pt=%.2f", FONT_DPI (the_font) / POINTS_PER_INCH);
ppp_widget = XtCreateManagedWidget ("ppp", labelWidgetClass,
form_widget, XTARG (ppp_args));
widget_to_the_left = ppp_widget;
#endif
XTASSIGN_ARG (item_args[0], widget_to_the_left);
XTASSIGN_ARG (item_args[1], utoa (FONT_CURRENT_CHARCODE (the_font)));
item_widget
= XtCreateManagedWidget ("current character item", itemWidgetClass,
form_widget, XTARG (item_args));
widget_to_the_left = item_widget;
XTASSIGN_ARG (position_args[0], item_widget);
position_widget = XtCreateManagedWidget ("position", labelWidgetClass,
form_widget, XTARG (position_args));
/* So much for the top row. The next row contains the left side
bearing and right side bearing items, and add/remove kern items. */
widget_above = prev_widget; /* Any in the top row would do. */
XTASSIGN_ARG (lsb_args[0], widget_above);
lsb_widget = XtCreateManagedWidget ("lsb item", itemWidgetClass,
form_widget, XTARG (lsb_args));
XTASSIGN_ARG (rsb_args[0], lsb_widget);
XTASSIGN_ARG (rsb_args[1], widget_above);
rsb_widget = XtCreateManagedWidget ("rsb item", itemWidgetClass,
form_widget, XTARG (rsb_args));
XTASSIGN_ARG (add_kern_args[0], rsb_widget);
XTASSIGN_ARG (add_kern_args[1], widget_above);
add_kern_widget = XtCreateManagedWidget ("+kern", itemWidgetClass,
form_widget, XTARG (add_kern_args));
XTASSIGN_ARG (remove_kern_args[0], add_kern_widget);
XTASSIGN_ARG (remove_kern_args[1], widget_above);
remove_kern_widget = XtCreateManagedWidget ("-kern", itemWidgetClass,
form_widget, XTARG (remove_kern_args));
/* The next row is the true-size bitmap. */
widget_above = lsb_widget;
XTASSIGN_ARG (true_bitmap_args[0], widget_above);
true_bitmap_widget = XtCreateManagedWidget ("true bitmap", bitmapWidgetClass,
form_widget, XTARG (true_bitmap_args));
/* The next row is the kern box. */
XTASSIGN_ARG (kern_box_args[0], true_bitmap_widget);
kern_box_widget = XtCreateManagedWidget ("kern box", boxWidgetClass,
form_widget, XTARG (kern_box_args));
/* The Viewport holds the editable bitmap. We don't want it to overlap
with any of the other windows, and yet we want to have as much
screen space as possible. So we put it below the previous row with
the lsb_widget, even though we've also put in the kern box and true
bitmap since then. To ensure that it doesn't overlap with those
two horizontally, we compute the width of a kern item, and the
width of 1em, and make that the distance from the left edge. This
fails if a character's width > 1em > width (kern item), but that is
an unlikely cirumstance. We don't find the actual width of the
widest character in the font, since then we would (perhaps) have to
read all its characters. */
XTASSIGN_ARG (viewport_args[0], lsb_widget);
{
unsigned box_border;
/* Compute an em in pixels. */
tfm_global_info_type tfm_info = FONT_TFM_FONT (FONT_INFO (the_font));
real em_points = TFM_SAFE_FONTDIMEN (tfm_info, TFM_QUAD_PARAMETER,
TFM_DESIGN_SIZE (tfm_info));
unsigned em_pixels = POINTS_TO_PIXELS (em_points, FONT_DPI (the_font));
/* Find the maximum width of a kern item. */
unsigned kern_item_width = find_kern_item_width (top);
/* Use the max, plus the border width of the kern box. We assume
the border width of the form and other widgets is zero. */
unsigned offset = MAX (em_pixels, kern_item_width);
XtVaGetValues (kern_box_widget, XtNborderWidth, &box_border, NULL, NULL);
offset += box_border * 2;
XTASSIGN_ARG (viewport_args[1], offset);
}
viewport_widget = XtCreateManagedWidget ("viewport", viewportWidgetClass,
form_widget, XTARG (viewport_args));
/* The Viewport will manage the editable Bitmap. We want the
`true_bitmap' to be updated when the Bitmap is edited, so assign to
the shadow resource. */
XTASSIGN_ARG (bitmap_args[0], true_bitmap_widget);
bitmap_widget = XtCreateManagedWidget ("bitmap", bitmapWidgetClass,
viewport_widget, XTARG (bitmap_args));
/* We want to show the coordinates of the pointer in the bitmap
widget whenever we have some spare time. We may as well pass the
widgets to the procedure. */
update_position_data = xmalloc (sizeof (Widget) * 2);
update_position_data[0] = position_widget;
update_position_data[1] = bitmap_widget;
(void) XtAddWorkProc (update_position, update_position_data);
show_char (form_widget, &the_font, initial_char);
}
/* This routine is called at idle times. We want to display the
coordinates of the pointer, if it's in the bitmap widget. We are
passed in CLIENT_DATA an array of two Widget pointers: the first is
the label we are supposed to display the information; the second is
the bitmap widget we are supposed to find the coordinates relative
to. Since it's more important to not consume cycles during periods
of work than to provide an accurate display at all times, we do
nothing at all on some percentage of calls. */
static Boolean
update_position (XtPointer client_data)
{
static char last_str[MAX_INT_LENGTH * 2 + 2] = "";
char str[sizeof (last_str)];
unsigned mask;
Window root_window, child_window;
int root_x, root_y, win_x, win_y;
Widget *widgets = (Widget *) client_data;
Widget bw = widgets[1];
real test_value = (real) k_rand ();
if (test_value / RAND_MAX < .75)
return False;
if (XQueryPointer (XtDisplay (bw), XtWindow (bw), &root_window,
&child_window, &root_x, &root_y, &win_x, &win_y, &mask))
{ /* They're on the same screen. Now see if the coordinate is
actually within the bitmap. */
unsigned expansion = BitmapExpansion (bw);
int row = win_y / expansion;
int col = win_x / expansion;
bitmap_type *bitmap = BitmapBits (bw);
if (row < 0 || row >= BITMAP_HEIGHT (*bitmap)
|| col < 0 || col >= BITMAP_WIDTH (*bitmap))
str[0] = 0;
else
sprintf (str, "%u,%u", col, row);
}
else
str[0] = 0;
if (!STREQ (str, last_str))
{
Widget lw = widgets[0];
XtVaSetValues (lw, XtNlabel, str, NULL, NULL);
strcpy (last_str, str);
}
/* We never want to be deleted from the work queue. */
return False;
}
/* Reading the options (besides the standard Xt options and our own X
options, which have already been removed). The arguments recognized
below do not have equivalents in X's resource database, nor should
they, particularly. So we don't want to give them to X to parse. */
/* This is defined in version.c. */
extern string version_string;
#define USAGE "Options:
<font_name> should be a filename, possibly with a resolution, e.g.,
`cmr10' or `cmr10.300'.\n" \
GETOPT_USAGE \
" The standard X toolkit options are also accepted. The class name is `XBfe'.
dpi <unsigned>: use this resolution; default is 300.
expansion <unsigned>: each pixel in the bitmap will be this many pixels
square on the display; default is 12. You can't use `=' here to
separate the option name and value. You can set this value by setting
a resource `expansion' in your .Xdefaults file.
initial-char <char>: start up displaying the character <char>; default is
the character in the font with the smallest code.
help: print this message.
output-file <filename>: use <filename> as the output file; default is
`<font_name>.<dpi>gf' and `<font_name>.tfm'.
version: print the version number of this program.
"
static string
read_command_line (int argc, string argv[])
{
int g; /* `getopt' return code. */
int option_index;
boolean explicit_dpi = false;
boolean printed_version = false;
struct option long_options[]
= { { "dpi", 1, (int *) &explicit_dpi, 1 },
{ "initial-char", 1, 0, 0 },
{ "help", 0, 0, 0 },
{ "output-file", 1, 0, 0 },
{ "version", 0, (int *) &printed_version, 1 },
{ 0, 0, 0, 0 } };
while (true)
{
g = getopt_long_only (argc, argv, "", long_options, &option_index);
if (g == EOF)
break;
if (g == '?')
continue; /* Unknown option. */
assert (g == 0); /* We have no short option names. */
if (ARGUMENT_IS ("dpi"))
dpi = optarg;
else if (ARGUMENT_IS ("initial-char"))
FONT_CURRENT_CHARCODE (the_font) = xparse_charcode (optarg);
else if (ARGUMENT_IS ("help"))
{
fprintf (stderr, "Usage: %s [options] <font_name>.\n", argv[0]);
fprintf (stderr, USAGE);
exit (0);
}
else if (ARGUMENT_IS ("output-file"))
output_name = optarg;
else if (ARGUMENT_IS ("version"))
printf ("%s.\n", version_string);
/* Else it was just a flag; getopt has already done the assignment. */
}
FINISH_COMMAND_LINE ();
}