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 >
Wrap
C/C++ Source or Header
|
1992-06-01
|
15KB
|
455 lines
/* commands.c: the operations we allow. The routines here are called
by the toolkit, as ``callbacks'', when certain events happen.
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 "Bitmap.h"
#include "font.h"
#include "gf.h"
#include "xmessage.h"
#include "char.h"
#include "commands.h"
#include "main.h"
/* The filename of the bitmap font we output. (-output-file) */
string output_name = NULL;
/* The names we construct for the output files. */
static string gf_output_name, tfm_output_name;
/* If the `true' output_names are non-null, we are using a temporary
output file, and should therefore do a copy when the user exits,
because the input and output files are the same. */
static string true_gf_output_name = NULL;
static string true_tfm_output_name = NULL;
static bitmap_type enlarge_bitmap (bitmap_type);
/* Exit the program. We set the callback up to pass the font name as
the CLIENT_DATA. */
void
exit_command (Widget w, XtPointer client_data, XtPointer call_data)
{
string font_name = client_data;
close_font (font_name);
if (true_gf_output_name != NULL)
xrename (gf_output_name, true_gf_output_name);
if (true_tfm_output_name != NULL)
xrename (tfm_output_name, true_tfm_output_name);
exit (0);
}
/* Move to the next character in the font. CLIENT_DATA is a pointer to
a `font_type' structure, and CALL_DATA is ignored. */
void
next_command (Widget w, XtPointer client_data, XtPointer call_data)
{
unsigned this_char;
char_type *c = NULL;
font_type *f = (font_type *) client_data;
for (this_char = FONT_CURRENT_CHARCODE (*f) + 1;
this_char <= MAX_CHARCODE && c == NULL;
this_char++)
c = read_char (*f, this_char);
if (c == NULL)
x_warning (XtParent (w), "You're at the last character");
else
show_char (XtParent (w), f, c);
}
/* Move to the previous character in the font. The arguments are the
same as for `next_command'. */
void
prev_command (Widget w, XtPointer client_data, XtPointer call_data)
{
int this_char;
char_type *c = NULL;
font_type *f = (font_type *) client_data;
for (this_char = FONT_CURRENT_CHARCODE (*f) - 1;
this_char >= 0 && c == NULL;
this_char--)
c = read_char (*f, this_char);
if (c == NULL)
x_warning (XtParent (w), "You're at the first character");
else
show_char (XtParent (w), f, c);
}
/* Go back to the image that is in the font file, killing all changes.
Since we made a copy of the bitmap before making changes, we free the
storage that the copy is occupying. It would be nice if we could
change the modified status of the font, but since we don't keep a
record, we don't know whether this character is the only one that has
changed. */
void
revert_command (Widget w, XtPointer client_data, XtPointer call_data)
{
char_type *c;
font_type *f = (font_type *) client_data;
charcode_type code = FONT_CURRENT_CHARCODE (*f);
char_type *original = FONT_CHAR (*f, code);
/* Set the pointer in the font structure to null, so `read_char' will
have to reread the character. */
FONT_CHAR (*f, code) = NULL;
/* Reread the character. */
c = read_char (*f, code);
if (c == NULL)
FATAL2 ("xbfe: Character %d has somehow been deleted from `%s'",
FONT_CURRENT_CHARCODE (*f), FONT_NAME (*f));
show_char (XtParent (w), f, c);
/* Release the storage the current character is using. We must do
this after rereading the character from the font, so that the same
memory is not used. If that happens, `bitmap_set_values' thinks
nothing has changed. */
free_bitmap (&BCHAR_BITMAP (*original));
free (original);
}
/* This is invoked when the user hits return (well, when the
`AcceptValue' action is executed) in the Item widget that allows
changing the current character. CLIENT_DATA is a pointer to a
`font_type' structure. CALL_DATA is the value string in the item
widget which the user typed; we hope it parses as a character code. */
void
char_change_callback (Widget w, XtPointer client_data, XtPointer call_data)
{
charcode_type charcode;
string value_string = call_data;
if (XTPARSE_CHARCODE (charcode, value_string, w))
{
font_type *f = (font_type *) client_data;
char_type *c = read_char (*f, charcode);
if (c == NULL)
x_warning (XtParent (w), "No such character");
else
show_char (XtParent (w), f, c);
}
}
/* Change the side bearing values. */
/* We allow the user to give just simple decimal constants. If we see
something else, give a warning. */
#define CHECK_DECIMAL(widget, str) \
if (!integer_ok (str)) \
{ \
string s = concat3 ("`", str, "': invalid integer"); \
x_warning (XtParent (widget), s); \
free (s); \
return; \
}
/* We have to do some things the same when either of the side bearings
changes. We change the character C according to the side-bearing
change of OFFSET pixels. Why did I make this a macro? */
#define COMMON_CHANGE(f, c, offset) \
{ \
char_info_type *char_info = &CHAR_BITMAP_INFO (*c); \
real ds = BITMAP_FONT_DESIGN_SIZE (FONT_BITMAP_FONT (FONT_INFO (*f)));\
real pt_width = fix_to_real (CHAR_TFM_WIDTH (*char_info) * ds); \
real pt_offset = PIXELS_TO_POINTS (offset, FONT_DPI (*f)); \
real new_tfm_width = pt_width + pt_offset; \
TFM_WIDTH (CHAR_TFM_INFO (*c)) = new_tfm_width; \
CHAR_TFM_WIDTH (*char_info) = real_to_fix (new_tfm_width / ds); \
CHAR_SET_WIDTH (*char_info) += offset; \
FONT_MODIFIED (*f) = true; \
}
void
lsb_change_callback (Widget w, XtPointer client_data, XtPointer call_data)
{
int new_lsb, old_lsb;
string value_string = call_data;
font_type *f = (font_type *) client_data;
char_type *c = FONT_CURRENT_CHAR (*f);
assert (c != NULL);
CHECK_DECIMAL (w, value_string);
old_lsb = CHAR_LSB (CHAR_BITMAP_INFO (*c));
new_lsb = atoi (value_string);
CHAR_MIN_COL (CHAR_BITMAP_INFO (*c)) = new_lsb;
CHAR_MAX_COL (CHAR_BITMAP_INFO (*c)) += new_lsb - old_lsb;
COMMON_CHANGE (f, c, new_lsb - old_lsb);
}
void
rsb_change_callback (Widget w, XtPointer client_data, XtPointer call_data)
{
int new_rsb, old_rsb;
string value_string = call_data;
font_type *f = (font_type *) client_data;
char_type *c = FONT_CURRENT_CHAR (*f);
assert (c != NULL);
CHECK_DECIMAL (w, value_string);
old_rsb = CHAR_RSB (CHAR_BITMAP_INFO (*c));
new_rsb = atoi (value_string);
COMMON_CHANGE (f, c, new_rsb - old_rsb);
}
/* Expand the bitmap by one pixel on all sides. */
void
expand_command (Widget w, XtPointer client_data, XtPointer call_data)
{
font_type *f = (font_type *) client_data;
/* We must use `*bitmap' here, since the editable Bitmap is a child of
the Viewport. Incidentally, R3's XtNameToWidget won't work here. */
Widget bw = XtNameToWidget (XtParent (w), "*bitmap");
bitmap_type *b = BitmapBits (bw);
char_type *c = XTALLOC1 (char_type);
/* Copy the current character, so the `*_set_values' commands can
notice something is changed. */
*c = *FONT_CURRENT_CHAR (*f);
/* Do the enlargement. */
BCHAR_BITMAP (*c) = enlarge_bitmap (*b);
/* We have to increase the bounding box for the character. The best
way to do this is not obvious. Right now, we arrange things so
that the origin of the character does not move, i.e., the new row
at the bottom is below the baseline, and the new column at the left
is into the side bearing. Perhaps we should have four separate
expand commands (or something along those lines). */
BCHAR_SET_WIDTH (*c) += 2;
BCHAR_MIN_COL (*c)--;
BCHAR_MAX_COL (*c)++;
BCHAR_MIN_ROW (*c)--;
BCHAR_MAX_ROW (*c)++;
/* Display the new values. */
show_char (XtParent (w), f, c);
/* Free afterwards; see revert_command. */
free_bitmap (b);
}
/* Expand the bitmap B by one pixel on all four sides. We return a new
bitmap. */
static bitmap_type
enlarge_bitmap (bitmap_type b)
{
bitmap_type new;
dimensions_type new_size;
unsigned row;
DIMENSIONS_WIDTH (new_size) = BITMAP_WIDTH (b) + 2;
DIMENSIONS_HEIGHT (new_size) = BITMAP_HEIGHT (b) + 2;
new = new_bitmap (new_size);
/* `new_bitmap' initializes all the pixels to white, so we don't have
to do anything to the new rows and columns. */
for (row = 1; row < DIMENSIONS_HEIGHT (new_size) - 1; row++)
{
one_byte *source = BITMAP_ROW (b, row - 1);
one_byte *target = BITMAP_ROW (new, row) + 1;
memcpy (target, source, BITMAP_WIDTH (b));
}
return new;
}
/* Save the font (if it's been modified). The CLIENT_DATA is a pointer
to a `font_type' structure, as defined in `main.h'. */
/* Write C, a `char_info_type', to the output file. */
#define OUTPUT_CHAR(c) \
do \
{ \
gf_char_type gf_char; \
\
GF_CHARCODE (gf_char) = this_char; \
GF_BITMAP (gf_char) = BCHAR_BITMAP (c); \
GF_CHAR_BB (gf_char) = BCHAR_BB (c); \
GF_H_ESCAPEMENT (gf_char) = BCHAR_SET_WIDTH (c); \
GF_TFM_WIDTH (gf_char) = BCHAR_TFM_WIDTH (c); \
gf_put_char (gf_char); \
\
tfm_put_char (CHAR_TFM_INFO (c)); \
} \
while (0)
/* We put this in the font comment to identify ourselves. */
#define OUR_PREFIX "Hand edited"
void
save_command (Widget w, XtPointer client_data, XtPointer call_data)
{
string font_comment, our_comment;
string pl_output_name;
unsigned this_char;
font_type *f_ptr = (font_type *) client_data;
font_type f = *f_ptr;
bitmap_font_type bitmap_font = FONT_BITMAP_FONT (FONT_INFO (f));
Widget bw = XtNameToWidget (XtParent (w), "*bitmap");
if (!(FONT_MODIFIED (f) || BitmapModified (bw)))
{
x_warning (XtParent (w),
"You didn't change the font, so I won't write it out");
return;
}
/* The output file is named the same thing as the input file (except
we always output in GF format), unless the user has specified an
output name. */
if (output_name == NULL)
output_name = basename (FONT_NAME (f));
gf_output_name = concat4 (output_name, ".", utoa ((unsigned) FONT_DPI (f)),
"gf");
pl_output_name = concat (output_name, ".pl");
tfm_output_name = concat (output_name, ".tfm");
/* Since the user can go on editing after a save, however, we must
make sure not to overwrite either of the input files. If they do
want to end up overwriting, we use a temporary file for writing.
Then, when the user exits, we'll copy the temporary back to the
real file. */
if (same_file_p (BITMAP_FONT_FILENAME (bitmap_font), gf_output_name))
{
string temp_dir = getenv ("TMPDIR") ? : "/tmp";
true_gf_output_name = gf_output_name;
gf_output_name = concat5 (temp_dir, "/", itoa (getpid ()),
basename (output_name), "gf");
}
if (same_file_p (FONT_TFM_FILENAME (FONT_INFO (f)), tfm_output_name))
{
string temp_dir = getenv ("TMPDIR") ? : "/tmp";
true_tfm_output_name = tfm_output_name;
tfm_output_name = concat4 (temp_dir, "/", itoa (getpid ()), ".tfm");
pl_output_name = concat4 (temp_dir, "/", itoa (getpid ()), ".pl");
}
/* Open the output files we will write to. */
if (!gf_open_output_file (gf_output_name))
FATAL_PERROR (gf_output_name);
if (!tfm_open_pl_output_file (pl_output_name))
FATAL_PERROR (pl_output_name);
/* Don't keep tacking on our prefix to the beginning of the comment;
instead, replace it if it's already there. Also, don't bother to
put the day of the week in the comment. */
our_comment = concat3 (OUR_PREFIX " ", now () + 4, " from ");
font_comment = FONT_COMMENT (FONT_INFO (f));
if (strncmp (font_comment, OUR_PREFIX, strlen (OUR_PREFIX)) == 0)
font_comment += strlen (our_comment);
/* Output the stuff at the beginning. */
gf_put_preamble (concat (our_comment, font_comment));
tfm_put_global_info (FONT_TFM_FONT (FONT_INFO (f)));
for (this_char = 0; this_char <= MAX_CHARCODE; this_char++)
{
char_type *c = FONT_CHAR (f, this_char);
/* First see if we've read this character, i.e., if the user has
edited (well, at least selected) it. */
if (c != NULL)
OUTPUT_CHAR (*c);
else
{
tfm_char_type *tfm_char;
/* The character hasn't been seen, so now we need to see if
it's in the font. If it is, though, there is no point in
doing all the work of decoding and then re-encoding the
bitmap, so we just read the raw bytes. */
raw_char_type *c = get_raw_char (FONT_NAME (f), this_char);
if (c != NULL && RAW_CHAR_BITMAP_FORMAT (*c) == gf_format)
{
/* We found it in the font, although the user hasn't seen
it yet. We just write out the same bytes that were
already present in the font file. */
gf_put_raw_char (*c);
free_raw_char (c);
/* Also output the TFM character, just as we read it. */
tfm_char = tfm_get_char (this_char);
if (tfm_char != NULL)
tfm_put_char (*tfm_char);
}
else
{ /* It's not available as a raw character in the right
format. We still have to test if it's available at all. */
char_type *c = read_char (f, this_char);
if (c != NULL)
{
OUTPUT_CHAR (*c);
/* We might as well save the character away, to avoid
reconstructing the bitmap if they either visit the
character or just save again. */
FONT_CHAR (f, this_char) = c;
}
}
}
}
gf_put_postamble (real_to_fix (FONT_DESIGN_SIZE (FONT_INFO (f))),
FONT_DPI (f), FONT_DPI (f));
/* Make the TFM file from the PL file. */
tfm_convert_pl (NULL, false);
/* Close the output files, since we will write them again from scratch
next time. */
gf_close_output_file ();
tfm_close_pl_output_file ();
}