#define  NOVIRTUALKEYCODES

#include "windows.h"
#include <windowsx.h>
#include "fontedit.h"
#include "fcntl.h"
#include <stdlib.h>   // Causes redefinition warnings.
#include <string.h>

/****************************************************************************/
/*              Shared Variables (Home base)                                */
/****************************************************************************/

FARPROC lpHeaderProc;                  /* Pointer to Dialog Box Procedure */
FARPROC lpReSizeProc;                  /* Pointer to Dialog Box Procedure */
FARPROC lpWidthProc;                   /* Pointer to Dialog Box Procedure */

FontHeaderType font;                    /* Structure of Font File Header */
LONG lSizeOfOldFontHeader = 0;                  /* Old packed header size.              */
LONG lSizeOfOldFontHeader30 = 0;                /* Old 3.0 packed header size.  */
LONG lSizeOfOldGlyph20 = 0;             /* Old packed 2.0 glyph info size. */
LONG lSizeOfOldGlyph30 = 0;                     /* Old packed 3.0 glyph info size. */
extern CHAR szFontFile[];               /* Name of Font File */
extern CHAR szFontFileFull[];               /* Name of Font File */
extern CHAR szNewFile[];                /* Temporary Name */
extern BOOL NewFile;                    /* flag indicating if file was opened
                                           by selecting NEW menu item */
HCURSOR hCross;                         /* handle to a "+" shaped cursor */
HANDLE hInst;                           /* Handle to Window Instance */
HANDLE hgPrev;
INT  swH = 0;                           /* Position in Show Window 0-100 */
BYTE iChar = 65;                        /* Character being edited */
BYTE jChar = 65;                        /* Last Char. of edit block */
CHAR szFaceName[szNamesMax] = {""};     /* Face Name of Font */
DWORD offsets[257];                     /* Offsets Table */
CHAR *vrgsz[CSTRINGS];                  /* string table */

BOOL fChanged = FALSE;                  /* Note if we did anything */
BOOL fLoaded = FALSE;                   /* Set if a font is loaded */
BOOL fEdited = FALSE;                   /* Character was edited */
INT  iFontFormat;                       /* Set to id of current font format */
INT  iFontFormatPrev;                   /* Set to id of prev. font format */
BOOL fReadOnly;

HWND hBox = NULL;                       /* Handle to Edit Window */
HWND hFont = NULL;                      /* Handle to Show window */
HDC hMemDC = NULL;                      /* Handle to Memory Display Context */
HBITMAP hBitmap = NULL;                 /* Handle to our work bit map */

CHAR matBox [wBoxLim] [kBoxLim];        /* array to hold Box */
WORD wBox = 10;                 /* Width of Character(s) */
WORD kBox = 16;                 /* Height of Characters */
DWORD kStuff;                   /* Height of font window caption etc. */

OFSTRUCT ofstrFile;             /* holds info of file - filled in by dlgopen/save */
//WORD     fp = NULL;             /* global fp of current file - " " " " " " */

/*** string arrays for using stringtable ***/
CHAR    szAppName[MAX_STR_LEN];
CHAR    szIFN[MAX_STR_LEN];         /* illegal filename */
CHAR    szFNF[MAX_STR_LEN];         /* file not found   */
CHAR    szREF[MAX_STR_LEN];         /* replace existing file */
CHAR    szSCC[MAX_STR_LEN];         /* save current changes */
CHAR    szEOF[MAX_STR_LEN];         /* error opening file */
CHAR    szECF[MAX_STR_LEN];         /* error creating file */
CHAR    szFRO[MAX_STR_LEN];         /* error creating file */
CHAR    szExt[MAX_STR_LEN];         /* .FNT */
CHAR    szExtDesc[MAX_STR_LEN];     /* Font Files(.FNT) */
CHAR    szNEWFONT[MAX_STR_LEN];     /* Font Files(.FNT) */
CHAR    szFilter[MAX_STR_LEN];     /* Font Files(.FNT) */


/* size of system font */
INT     cSysWidth;
INT     cSysHeight;

/****************************************************************************/
/*              Local Variables                                             */
/****************************************************************************/

BYTE FindMouse();               /* Find where mouse is */

HBRUSH hbrWhite;
HBRUSH hbrBlack;
HBRUSH hbrGray;
HBRUSH hbrDkGray;
HBRUSH hbrBackGround;

BYTE downChar;                          /* Where mouse was pressed */
BYTE lastChar;                          /* Where mouse was last */
WORD wBoxOld;                           /* So we can catch any changes */
RECT rectWin;                           /* Client Rectangle */
LONG origin;                           /* Position in Show Window pixels */
BOOL fFirstShow = TRUE;                /* first time Show Window displayed? */

/****************************************************************************/
/*              Local Functions                                             */
/****************************************************************************/

VOID InvertFont(HDC, BYTE, BYTE);
BOOL FontEditInit(HANDLE);
VOID InitSizes(VOID);

/*****************************************************************************
 * FontShowHorzScroll(hFont, code, posNew)
 *
 * purpose: intepret scroll message for tiny window and call scroll funtion
 *          accordingly
 *
 * params: HWND hFont : handle to tiny window
 *         int code   : scroll message
 *         int posNew : thumb position
 * returns: none
 *
 * side effects: scroll position variable altered
 *
 ****************************************************************************/
VOID
FontShowHorzScroll(
    HWND hFont,
    INT code,
    INT posNew
        )
{
    WORD   wChar;
    RECT   rect;

    /* Get dimensions */
    GetClientRect(hFont, (LPRECT)&rect);

    if (font.AvgWidth == 0 ) { // for Japan
        font.AvgWidth = 1 ;
        }
    /* Make a fair guess as to how many characters are in the window */
    /* Convert sorta to hex too. */
    wChar=(WORD)(11*(rect.right-rect.left)/(font.AvgWidth*16));

    switch (code)
        {
        case SB_LINEUP:     /* line left */
            swH -= 1;
            break;
        case SB_LINEDOWN:   /* line right */
            swH += 1;
            break;
        case SB_PAGEUP:     /* page left */
            swH -= wChar;
            break;
        case SB_PAGEDOWN:   /* page right */
            swH += wChar;
            break;
        case SB_THUMBPOSITION:
            swH = posNew;
            break;
        case SB_THUMBTRACK:
            return;
    }
    ScrollFont();
}

/*****************************************************************************
 * FontShowPaint(hDC)
 *
 * purpose: repaint the little window at the bottom
 *
 * params:  HDC hDC : handle to display context.
 *
 * returns: none
 *
 * side effects: some scroll globals altered.
 *
 ****************************************************************************/

VOID
FontShowPaint(
        HDC hDC
        )
{
        DWORD range, nBits;
        INT nx;

    nx=GetSystemMetrics(SM_CXBORDER);
    /* 320 --> 300 */
    nBits = min(300, rectWin.right - rectWin.left-nx-nx) - 24;
        /* Window width (pixels) */
    /* 320 --> 300 */
    range = max(0, (font.WidthBytes << 3) - min(300, nBits));
    origin = (swH * range) / 100;               /* Global variable */
    BitBlt(hDC, 12, 2, nBits, font.PixHeight,
           hMemDC, origin, 0, NOTSRCCOPY);
    /* Now highlight the current value of iChar */
    InvertFont(hDC, iChar, jChar);
}


/*****************************************************************************
 * MouseInFont(ptMouse)
 *
 * purpose: Select new char in tiny Show window by inverting current char
 *          and un-inverting last one
 *
 * params:  POINT ptMouse  : mouse coordinates
 *
 * returns: none
 *
 * side effects: pixels inverted(uninverted) in bitmap.
 *
 ****************************************************************************/
VOID
MouseInFont(
        POINT ptMouse                    /*  .. to get new iChar */
        )
{
        HDC hDC;

    BoxToChar(iChar);           /* Replace edited character in Box if changed */
    hDC = GetDC(hFont);
    /* UnInvert present inverted region */
    InvertFont(hDC, iChar, jChar);
    /* Find where mouse is */
    lastChar = downChar = iChar = jChar = FindMouse(ptMouse);
    /* Invert Character touched */
    InvertFont(hDC, iChar, jChar);
    ReleaseDC(hFont, hDC);
}


/*****************************************************************************
 *
 * purpose:
 *
 * params:
 *
 * returns:
 *
 * side effects:
 *
 ****************************************************************************/
VOID
MouseMoveFont(
        POINT ptMouse
        )
        /* Mouse raised in font */
        /*  .. to get new jChar */
{
        UNREFERENCED_PARAMETER(ptMouse);
    return;     /********* NOT YET IN USE !! ********/

#if 0
        BYTE newChar;
        HDC hDC;

    newChar = FindMouse(ptMouse);               /* Find where mouse is */
    if (newChar == lastChar)            /* Did we move ? */
        return;                         /* No: return */
    lastChar = newChar;
    hDC = GetDC(hFont);
    if (newChar > jChar)
        {
        InvertFont(hDC, jChar + 1, newChar);    /* extend jChar */
        jChar = newChar;
        }
    else if (newChar < iChar)           /* iChar & jChar switch */
        {
        InvertFont(hDC, newChar, iChar - 1);
        iChar = newChar;
        }
    else
        {
        if (newChar >= downChar)        /* width reduced on right */
            {
            InvertFont(hDC, newChar + 1, jChar);
            jChar = newChar;
            }
        if (newChar <= downChar)        /* width reduced on left */
            {
            InvertFont(hDC, iChar, newChar - 1);
            iChar = newChar;
            }
        }
    ReleaseDC(hFont, hDC);
#endif
}


/*****************************************************************************
 * InvertFont(hDC, iChar, jChar)
 *
 * purpose: inverts color on selected chars (iChar thro' jChar) in the Show
 *          Window
 *
 * params:  HDC hDC    : handle to display context
 *          char iChar : start char
 *          char jChar : end char
 *
 * returns: none
 *
 * side effects: changes pixel values in bitmap
 *
 ****************************************************************************/
VOID
InvertFont(
        HDC hDC,
        BYTE iChar,
        BYTE jChar
        )
{
    PatBlt(hDC,                         /* Use Blt to Invert it */
        12 + offsets[iChar] - origin,   /* X: Position */
        2,                              /* Y: Allow for top band */
        offsets[jChar + 1] - offsets[iChar],    /* dx: Compute width */
        font.PixHeight,                 /* dy: Look up the Height */
        DSTINVERT);                     /* Z: Tell it to invert it */
}


/*****************************************************************************
 * MouseOutFont(ptMouse)
 *
 * purpose: brings selected char to edit box and sets up tiny window for
 *          repainting
 *
 * params:  POINT ptMouse : mouse location
 *
 * returns: none
 *
 * side effects: changes matBox(2-d array containing ready pixel info. on
 *               char being edited)
 *
 ****************************************************************************/
VOID
MouseOutFont(
        POINT ptMouse
        )
        /* Mouse raised in font */
        /*  .. to get new jChar */
{
    MouseMoveFont(ptMouse);     /* Check on iChar and jChar */
    CharToBox(iChar);
    InvalidateRect(hFont, (LPRECT)NULL, TRUE);  /* Cause repaint */
}


/*****************************************************************************
 * BYTE FindMouse(ptMouse)
 *
 * purpose: Locate number of character(in tiny window at bottom) under mouse
 *
 * params:  POINT ptMouse : mouse location
 *
 * returns: number of character
 *
 * side effects: alters scroll position variable
 *
 ****************************************************************************/

BYTE
FindMouse(
        POINT ptMouse
        )
{
        int  iChar;
        LONG   x;


    x = ptMouse.x + origin - 12;        /* Horizontal position of mouse */
    if (x < 0)
        iChar = font.FirstChar;
    else
        {
        iChar = x / font.AvgWidth + font.FirstChar;
        /* Right if Fixed Pitch -- Best Guess if variable width */
        if (!font.PixWidth)                     /* Scan for new iChar */
            {
            if (iChar > (int)font.LastChar)
                   iChar = (int)font.LastChar;  /* Don't overshoot */

            while (iChar < (int)font.LastChar && offsets[iChar] < (DWORD)x)
                iChar++;
            while (iChar > (int)font.FirstChar && offsets[iChar] > (DWORD)x)
                iChar--;
            }
        }

    /* Bug fix: prevent nil character from showing if mouse is pressed way
       over on right side of font scroll with narrow fixed fonts. */
    if (iChar > (int)font.LastChar)
        iChar = (int)font.LastChar;  /* Don't overshoot */

    if (iChar < (int)font.FirstChar)
        iChar = (int)font.FirstChar;  /* Don't undershoot */

    if (ptMouse.x <= 12L)
        {
        swH -= 1;
        ScrollFont();
        }
    if (ptMouse.x > 308L)
        {
        swH += 1;
        ScrollFont();
        }
    return (BYTE)iChar;
}


/*****************************************************************************
 * ScrollFont()
 *
 * purpose: scrolls tiny window at bottom
 *
 * params:  none
 *
 * returns: none
 *
 * side effects: alters scroll position variable
 *
 ****************************************************************************/
VOID
ScrollFont(
        VOID
        )
{
        HDC hDC;

    swH = max(0, swH);
    swH = min(100, swH);        /* maintain 0 - 100 range */
    SetScrollPos(hFont, SB_HORZ, swH, TRUE);     /* Move thumb */
    hDC = GetDC(hFont);
    FontShowPaint(hDC);
    ReleaseDC(hFont, hDC);
}


/*****************************************************************************
 * BoxToChar(iChar)
 *
 * purpose: sets pixels in bitmap according to matBox(2-d array containing
 *          ready pixel info. on char being edited)
 *
 * params:  BYTE iChar : index of char in bitmap offset array(offsets)
 *
 * returns: none
 *
 * side effects: changes font bitmap
 *
 ****************************************************************************/
VOID
BoxToChar(
        BYTE iChar
        )
{
        DWORD x, y, offset;

    if (!fEdited)
        return;

    if (wBox != wBoxOld)                /* I.e if width has changed */
        CharWidth(iChar, wBox);         /* .. go fix it */

    offset = offsets[iChar];
    for (x = 0; x < wBox; x++)
        {
        for (y = 0; y < kBox; y++)
            SetPixel(hMemDC, offset + x, y,
                matBox[x] [y] == TRUE ? WHITE : BLACK);
        }
    fEdited = FALSE;
}


/*****************************************************************************
 * CharToBox(iChar)
 *
 * purpose: assigns matBox(2-d array containing ready pixel info. on char being
 *          edited) according to pixels in portion of bitmap corresp. to char.
 *
 * params:  BYTE iChar : index of char in bitmap offset array(offsets)
 *
 * returns: none
 *
 * side effects: changes matBox
 *
 ****************************************************************************/
VOID
CharToBox(
        BYTE iChar
        )
{
        DWORD x, y, offset;
        HMENU hMenu;

    ClearBox();
    offset = offsets[iChar];
    wBox = wBoxOld = (WORD) (offsets[iChar + 1] - offset); /* Edit Box width */
    kBox = font.PixHeight;                              /* Edit Box Height */
    for (x = 0; x < wBox; x++)
        for (y = 0; y < kBox; y++)
            matBox[x][y] = (BYTE) (GetPixel(hMemDC, offset + x, y) ? 1 : 0);
    InvalidateRect(hBox, (LPRECT)NULL, TRUE);
    fEdited = FALSE;            /* Not Changed Yet */
    hMenu = GetMenu(hBox);
    EnableMenuItem(hMenu, BOX_UNDO, MF_GRAYED);
    EnableMenuItem(hMenu, BOX_REFRESH, MF_GRAYED);
}


/*****************************************************************************/
/*              WinMain  and  Friends                                        */
/*****************************************************************************/


/* Procedure called every time a new instance of the application
** is created */

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, INT cmdShow)
{
        MSG    msg;
        WORD   message;
        INT    nx;
        HANDLE hAccel;

    hInst = hInstance;
    hgPrev=hPrevInstance;


        if (!FontEditInit( hInstance ))
            return FALSE;



    LoadString(hInstance, IDS_APPNAME, szAppName, MAX_STR_LEN);
    LoadString(hInstance, IDS_IFN, szIFN, MAX_STR_LEN); /* illegal filename */
    LoadString(hInstance, IDS_FNF, szFNF, MAX_STR_LEN); /* file not found   */
    LoadString(hInstance, IDS_REF, szREF, MAX_STR_LEN);
                        /* replace existing file */
    LoadString(hInstance, IDS_SCC, szSCC, MAX_STR_LEN);
                        /* save current changes */
    LoadString(hInstance, IDS_EOF, szEOF, MAX_STR_LEN); /* error opening file */
    LoadString(hInstance, IDS_ECF, szECF, MAX_STR_LEN);
        // File is read only.
    LoadString(hInstance, IDS_FRO, szFRO, MAX_STR_LEN);
                        /* error creating file */
    LoadString(hInstance, IDS_EXT, szExt, MAX_STR_LEN); /* default file ext. */

        // File extension description for common dialog.
    LoadString(hInstance, IDS_EXTDESC, szExtDesc, MAX_STR_LEN);
        // Message for new font warning box.
    LoadString(hInstance, IDS_NEW_FONT, szNEWFONT, MAX_STR_LEN);
    memset(szFilter, 0, MAX_STR_LEN);
    LoadString(hInstance, IDS_EXTDESC, szFilter, MAX_STR_LEN);
    LoadString(hInstance, IDS_STARDOTFNT, szFilter+strlen(szFilter)+1,
                                MAX_STR_LEN-(strlen(szFilter)+1));


    ClearBox();

        /* Create a window instance of class "FontEdit" */

    hBox = CreateWindow((LPSTR) vszFontEdit,
                      (LPSTR)szAppName,
                      WS_TILEDWINDOW,
                      56,34,
                      GetSystemMetrics(SM_CXFULLSCREEN)/2,
                      GetSystemMetrics(SM_CYFULLSCREEN)/2,
                      (HWND)NULL,        /* no parent */
                      (HMENU)NULL,       /* use class menu */
                      (HANDLE)hInstance, /* handle to window instance */
                      (LPSTR)NULL        /* no params to pass on */
                      );

    ShowWindow(hBox, cmdShow);
    UpdateWindow(hBox);
    InitSizes();     /* 11/21/86 - linsh - get system char width & height */


    GetWindowRect(hBox, (LPRECT)&rectWin);
    nx=GetSystemMetrics(SM_CXBORDER);
    hFont = CreateWindow((LPSTR) vszFontShow,
                       (LPSTR) "",
                       WS_BORDER|WS_HSCROLL|WS_CAPTION,
                       rectWin.left,
                       rectWin.bottom-56,
                       min(300, rectWin.right - rectWin.left-nx-nx),
                       50 - GetSystemMetrics(SM_CYBORDER),
                       (HWND)hBox,
                       (HMENU)NULL,
                       (HANDLE)hInstance,
                       (LPSTR)NULL
                       );


    /* Get address of Dialog Box procedure */
    lpHeaderProc = MakeProcInstance((FARPROC)HeaderProc, hInstance);
    lpReSizeProc = MakeProcInstance((FARPROC)ReSizeProc, hInstance);
    lpWidthProc = MakeProcInstance((FARPROC)WidthProc, hInstance);

    /* Start it loading if it's not iconic */
    if (!IsIconic(hBox))
        {
        if (lpszCmdLine[0])     /* If we have a font name use it */
            {
            BOOL   fDot;
            INT   i;

            /* Copy the specified file and make it upper case */
            lstrcpy((LPSTR)szFontFile, CharUpper((LPSTR)lpszCmdLine));

            fDot = FALSE;
            nx=lstrlen((LPSTR)szFontFile);

            for (i = 0; i < nx; i++)
                {
                if (szFontFile[i] == '.')       /* Add .FNT if none */
                    fDot = TRUE;

                if (szFontFile[i] == ' ')
                    szFontFile[i]=0;
                }

            if (!fDot)
                lstrcat((LPSTR)szFontFile, (LPSTR)vszDotFNT);

            lstrcpy((LPSTR)szNewFile, (LPSTR)szFontFile);

            /* Do this thing that someone forgot.  THe dialog open does it
               and affects the Save As initialization. */
            (HFILE)OpenFile((LPSTR)szNewFile, &ofstrFile, OF_READ);

            message = FONT_START;
            }
        else            /* Start by doing a regular file load */
            message = FONT_LOAD;

        SetFocus(hBox);
        PostMessage(hBox, WM_COMMAND, message, (LONG)0);
        }

    if (!fLoaded)
        ShowWindow(hFont, SW_HIDE);

    hAccel=LoadAccelerators(hInstance, "FE");

    /* Quit message will terminate application */
    while (GetMessage((LPMSG)&msg, NULL, 0, 0))
        {
        if (!TranslateAccelerator (hBox, hAccel, &msg))
            {
            TranslateMessage((LPMSG)&msg);
            DispatchMessage((LPMSG)&msg);
            }
        }

    return msg.wParam;
}

/*****************************************************************************
 * int FontEditInit( hInstance )
 *
 * purpose: Initialises a whole lot of stuff
 *
 * params:  HANDLE hInstance : handle to instance of application
 *
 * returns:     TRUE : if everything goes off well
 *             FALSE : error in initialisation
 *
 * side effects: a whole lot
 *
 ****************************************************************************/

/* Procedure called when the application is loaded */
BOOL
FontEditInit(
        HANDLE hInstance
        )
{
    INT cch;          /* all variables used to load srings from .RC file */
    INT cchRemaining;
    CHAR *pch;
    HANDLE hStrings;
    INT i;
    CHAR ColorStr[CCHCOLORSTRING]; /* background color inf. fronm win.ini */
    BYTE bR, bG, bB;  /* the three primary color values ret. from win.ini */
    // CHAR cDummy;      /* dummy char to hold the " " char */
    PWNDCLASS   pFontEditClass;         /* Edit Box window class */
    PWNDCLASS   pFontShowClass;         /* Show Font window class */

        //
        // Initialize the conversion routines to read in the old font structure
        // off of disk.
        //

        if (fConvStructInit () == FALSE) {

                return FALSE;
        }

    /* load strings from resource file */
    if (!(pch = (CHAR *)(hStrings =
                LocalAlloc (LPTR, cchRemaining = CCHSTRINGSMAX))))
          return FALSE;        /* unable to alloc. Try increasing initial
                                  heapsize in .DEf file */
    for (i=0; i< CSTRINGS; i++){
        cch = 1+LoadString (hInstance, (WORD) i, (LPTSTR)pch, cchRemaining);
        if (cch < 2){
            return FALSE;
                }
        vrgsz[i] = pch;
        pch += cch;
        if ((cchRemaining -= cch ) <= 0)
            return FALSE;
    }

    /* Allocate class structure in local heap */
    pFontEditClass = (PWNDCLASS)LocalAlloc( LPTR, sizeof(WNDCLASS) );
    if (pFontEditClass == NULL)
        return FALSE;

    /* set up some default brushes */
    hbrWhite = GetStockObject( WHITE_BRUSH );
    hbrBlack = GetStockObject( BLACK_BRUSH );
    hbrGray  = GetStockObject( GRAY_BRUSH );
    hbrDkGray  = GetStockObject( DKGRAY_BRUSH );

    /* get App. Workspace color from win.ini - LR */
    if (GetProfileString(vszcolors, vszAppWorkspace, "",ColorStr,
                                                       CCHCOLORSTRING)){
        bR = (BYTE)atoi((const char *)strtok (ColorStr, " "));
        bG = (BYTE)atoi((const char *)strtok (NULL, " "));
        bB = (BYTE)atoi((const char *)strtok (NULL, "\n"));
        hbrBackGround = CreateSolidBrush(RGB(bR, bG, bB));
    }
    else  /* set to lt. blue background */
        hbrBackGround = CreateSolidBrush((LONG)0x00FF8000);

    /* get necessary resources */
    pFontEditClass->hCursor  = LoadCursor( NULL, IDC_ARROW);
    pFontEditClass->hIcon    = LoadIcon( hInstance,(LPSTR)vszFontEdit);
    pFontEditClass->lpszMenuName = (LPSTR)vszFontEdit;
    pFontEditClass->lpszClassName = (LPSTR)vszFontEdit;
    pFontEditClass->hbrBackground = hbrBackGround;
    pFontEditClass->hInstance     = hInstance;

    pFontEditClass->style = CS_VREDRAW | CS_HREDRAW;

    /* Register our Window Proc */
    pFontEditClass->lpfnWndProc = (WNDPROC)FontEditWndProc;

    /* register this new class with WINDOWS */
    if (!hgPrev)
        if (!RegisterClass( (LPWNDCLASS)pFontEditClass ) )
            return FALSE;   /* Initialization failed */

    /* Now repeat the performance for the Show window */

    pFontShowClass = pFontEditClass;
    /* get necessary resources */
    pFontShowClass->hCursor  = LoadCursor(NULL,IDC_ARROW);
    pFontShowClass->hIcon    = (HICON)NULL;
    pFontShowClass->lpszMenuName = (HMENU)NULL;
    pFontShowClass->lpszClassName = (LPSTR)vszFontShow;
    pFontShowClass->hbrBackground = hbrGray;
    pFontShowClass->hInstance     = hInstance;
    pFontShowClass->style = CS_VREDRAW | CS_HREDRAW;

    /* Register our Window Proc */
    pFontShowClass->lpfnWndProc = (WNDPROC)FontShowWndProc;

    /* register this new class with WINDOWS */
    if (!hgPrev)
        if (!RegisterClass( (LPWNDCLASS)pFontShowClass ) )
            return FALSE;   /* Initialization failed */

    LocalFree( (HANDLE)pFontShowClass );

    return TRUE;    /* Initialization succeeded */
}

/*****************************************************************************
 * InitSizes()
 *
 * purpose: gets system char width and height
 *
 * params:  none
 *
 * returns: none
 *
 * side effects: sets width and height globals
 *
 ****************************************************************************/
VOID
InitSizes(
        VOID
        )
{
    HDC hDC;
    TEXTMETRIC tm;

    hDC = GetDC(hFont);
    GetTextMetrics(hDC, (LPTEXTMETRIC) &tm);
    cSysHeight = tm.tmHeight + tm.tmExternalLeading;;
    cSysWidth  = tm.tmAveCharWidth;
    ReleaseDC(hFont, hDC);
}


/*****************************************************************************
 * long  APIENTRY FontShowWndProc(hFont, message, wParam, lParam)
 *
 * purpose: Window function for tiny window at the bottom (showing font chars)
 *          Independently processes paint, scroll, keyboard and mouse
 *          messages for the window
 *
 * params:  as for window functions
 *
 * side effects: lots
 *
 ****************************************************************************/

/* Procedures which make up the window class. */
LONG  APIENTRY
FontShowWndProc(
        HWND   hFont,
        WORD   message,
        WPARAM wParam,
        LPARAM lParam
        )
{
        PAINTSTRUCT  ps;
        // RECT         rectWin;
        POINT        pt;

        ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y);

    switch (message)
    {

        case WM_SIZE :
            switch (wParam){
                /* if main window is iconised, hide the child window */
                case SIZEICONIC :
                    ShowWindow(hFont, SW_HIDE);
                    break;
                default:
                    return(DefWindowProc(hFont, message, wParam, lParam));
                    break;
            }
            break;


        case WM_PAINT:
            /* Time for the window to draw itself. */
            BeginPaint(hFont, (LPPAINTSTRUCT)&ps);
            FontShowPaint(ps.hdc);
            EndPaint(hFont, (LPPAINTSTRUCT)&ps);
            break;

        /* For each of following mouse window messages, wParam contains
        ** bits indicating whether or not various virtual keys are down,
        ** and lParam is a POINT containing the mouse coordinates.   The
        ** keydown bits of wParam are:  MK_LBUTTON (set if Left Button is
        ** down); MK_RBUTTON (set if Right Button is down); MK_SHIFT (set
        ** if Shift Key is down); MK_ALTERNATE (set if Alt Key is down);
        ** and MK_CONTROL (set if Control Key is down). */

        case WM_LBUTTONDOWN:
            MouseInFont(pt);              /* .. set iChar */
            break;
        case WM_LBUTTONUP:
            MouseOutFont(pt);     /* .. set jChar */
            break;
        case WM_RBUTTONDOWN:
        case WM_RBUTTONUP:
        case WM_MOUSEMOVE:                      /* If mouse is down */
            if (wParam & MK_LBUTTON)
                MouseMoveFont(pt);        /* .. set jChar */
            break;
        case WM_LBUTTONDBLCLK:
        case WM_RBUTTONDBLCLK:
            break;

        case WM_HSCROLL:
            /* wParam contains the scroll code.
            ** For the thumb movement codes, the low
            ** word of lParam contain the new scroll position.
            ** Possible values for wParam are: SB_LINEUP, SB_LINEDOWN,
            ** SB_PAGEUP, SB_PAGEDOWN, SB_THUMBPOSITION, SB_THUMBTRACK */
            /* Horizontal scroll bar input.  Parameters same as for
            ** WM_HSCROLL.  UP and DOWN should be interpreted as LEFT
            ** and RIGHT, respectively. */
            FontShowHorzScroll(hFont, LOWORD(wParam),
                                HIWORD(wParam));
            break;
        case WM_CLOSE:
            break;   /* don't allow this window to be closed before
                        bigger one */

        default:

            /* Everything else comes here.  This call MUST exist
            ** in your window proc.  */

            return(DefWindowProc(hFont, message, wParam, lParam));
            break;

    }

    /* A window proc should always return something */
    return(0L);
}


VOID
FontRename(
        CHAR * szError
        )
{
    CHAR *szTitle[MAX_STR_LEN+MAX_FNAME_LEN];

    if (szError[0])
        ErrorBox(hBox, szError);
    else
        {
        lstrcpy((LPSTR)szFontFileFull, (LPSTR)szNewFile);
        lstrcpy((LPSTR)szTitle, (LPSTR)szAppName);
        lstrcat((LPSTR)szTitle, (LPSTR)vszBlankDashBlank);
        lstrcat((LPSTR)szTitle, (LPSTR)szFontFile);
        SetWindowText(hBox, (LPSTR)szTitle);
        }
}


/*****************************************************************************
 * ResizeShow()
 *
 * purpose:   resize tiny window at bottom (showing font chars) in proportion
 *            to large window
 *
 * params:    none
 *
 * returns:   none
 *
 * side effects:
 *
 ****************************************************************************/

VOID
ResizeShow(
        VOID
        )
{
        INT    height;
        INT    nx;

    /* size message for hbox goes thru before hfont created. 06-Jul-1987. */
    if (!hFont)
        return;

    GetWindowRect(hBox, (LPRECT)&rectWin);
    kStuff = GetkStuff();               /* For check on second pass */

#if 0
    height = font.PixHeight + kStuff + 20;  /* 4 Height we want box */
#else
    height = font.PixHeight + GetSystemMetrics(SM_CYHSCROLL)
                            + GetSystemMetrics(SM_CYCAPTION)
                            + 4*GetSystemMetrics(SM_CYBORDER)/*20*/;     /* 4*/
#endif

     nx=GetSystemMetrics(SM_CXBORDER);
     MoveWindow(hFont,
                rectWin.left +nx+4,
                rectWin.bottom - (height + GetSystemMetrics(SM_CYBORDER)+2),
                min(300, rectWin.right - rectWin.left-nx-nx),
                height,
                TRUE);
    if (!IsWindowVisible(hFont) && fLoaded)
        ShowWindow(hFont, SW_SHOW);
}


DWORD
GetkStuff(
        VOID
        )     /* Get size of menu, scrollbar etc. */
{
        RECT rect, rectWin;

    /* size message for hbox goes thru before hfont created. 06-Jul-1987. */
    if (!hFont)
        return 0;

    GetClientRect(hFont, (LPRECT)&rect);     /* How much do WE get? */
    GetWindowRect(hFont, (LPRECT)&rectWin);
    return (DWORD) (rectWin.bottom - rectWin.top) - (rect.bottom - rect.top);
}
