reactos/rosapps/devutils/vgafontedit/fontboxeswnd.c
Colin Finck 7901978873 Wrote a Win32 Font Editor for our VGA Fonts used in blue.sys.
It has a MDI user interface, imports binary fonts (.bin) and PC Screen Fonts (.psf) and exports .bin fonts.
Compiles without any warnings with GCC and MSVC (at /W3).

The "misc.c" file was taken from devmgmt (thanks Ged!) and modified.
The used bitmaps and icons were all done myself, but partly consist of characters of the cp737 font we have in media/vgafont.

svn path=/trunk/; revision=32079
2008-02-01 21:40:18 +00:00

325 lines
11 KiB
C

/*
* PROJECT: ReactOS VGA Font Editor
* LICENSE: GNU General Public License Version 2.0 or any later version
* FILE: devutils/vgafontedit/fontboxeswnd.c
* PURPOSE: Implements the window showing the character boxes for a font
* COPYRIGHT: Copyright 2008 Colin Finck <mail@colinfinck.de>
*/
#include "precomp.h"
static const WCHAR szFontBoxesWndClass[] = L"VGAFontEditFontBoxesWndClass";
static VOID
DrawCharacterPixel(IN PAINTSTRUCT *ps, IN UINT uCharacter, IN UCHAR uRow, IN UCHAR uColumn, IN UCHAR uBit, IN COLORREF clBackground)
{
INT x;
INT y;
x = (uCharacter % 16) * (CHARACTER_BOX_WIDTH + CHARACTER_BOX_PADDING) + 24 + uColumn;
y = (uCharacter / 16) * (CHARACTER_BOX_HEIGHT + CHARACTER_BOX_PADDING)+ 1 + CHARACTER_INFO_BOX_HEIGHT + 2 + uRow;
SetPixel( ps->hdc, x, y, (uBit ? 0 : clBackground) );
}
VOID
GetCharacterRect(IN UINT uFontRow, IN UINT uFontColumn, OUT LPRECT CharacterRect)
{
CharacterRect->left = uFontColumn * (CHARACTER_BOX_WIDTH + CHARACTER_BOX_PADDING);
CharacterRect->top = uFontRow * (CHARACTER_BOX_HEIGHT + CHARACTER_BOX_PADDING);
CharacterRect->right = CharacterRect->left + CHARACTER_BOX_WIDTH;
CharacterRect->bottom = CharacterRect->top + CHARACTER_BOX_HEIGHT;
}
__inline VOID
GetCharacterPosition(IN UINT uCharacter, OUT PUINT uFontRow, OUT PUINT uFontColumn)
{
*uFontRow = uCharacter / 16;
*uFontColumn = uCharacter % 16;
}
static INT
FontBoxesHitTest(IN UINT xPos, IN UINT yPos, OUT LPRECT CharacterRect)
{
UINT uFontColumn;
UINT uFontRow;
uFontColumn = xPos / (CHARACTER_BOX_WIDTH + CHARACTER_BOX_PADDING);
uFontRow = yPos / (CHARACTER_BOX_HEIGHT + CHARACTER_BOX_PADDING);
GetCharacterRect(uFontRow, uFontColumn, CharacterRect);
if(xPos > (UINT)CharacterRect->right || yPos > (UINT)CharacterRect->bottom)
// The user clicked on separator space, so return HITTEST_SEPARATOR
return HITTEST_SEPARATOR;
else
// Return the character number
return (uFontRow * 16 + uFontColumn);
}
static VOID
SetSelectedCharacter(IN PFONT_WND_INFO Info, IN UINT uNewCharacter, OPTIONAL IN LPRECT NewCharacterRect)
{
LPRECT pCharacterRect;
RECT OldCharacterRect;
UINT uFontColumn;
UINT uFontRow;
// Remove the selection of the old character
GetCharacterPosition(Info->uSelectedCharacter, &uFontRow, &uFontColumn);
GetCharacterRect(uFontRow, uFontColumn, &OldCharacterRect);
InvalidateRect(Info->hFontBoxesWnd, &OldCharacterRect, FALSE);
// You may pass the RECT of the new character, otherwise we'll allocate memory for one and get it ourselves
if(NewCharacterRect)
pCharacterRect = NewCharacterRect;
else
{
GetCharacterPosition(uNewCharacter, &uFontRow, &uFontColumn);
pCharacterRect = (LPRECT) HeapAlloc( hProcessHeap, 0, sizeof(RECT) );
GetCharacterRect(uFontRow, uFontColumn, pCharacterRect);
}
// Select the new character
Info->uSelectedCharacter = uNewCharacter;
InvalidateRect(Info->hFontBoxesWnd, pCharacterRect, FALSE);
if(!NewCharacterRect)
HeapFree(hProcessHeap, 0, pCharacterRect);
}
static VOID
DrawProc(IN PFONT_WND_INFO Info, IN PAINTSTRUCT* ps)
{
COLORREF clBackground;
HBRUSH hBrush = 0;
HBRUSH hOldBrush = 0;
HDC hBoxDC;
HFONT hFont;
HFONT hOldFont;
RECT CharacterRect;
UINT uFontColumn;
UINT uStartColumn;
UINT uEndColumn;
UINT uFontRow;
UINT uStartRow;
UINT uEndRow;
UINT uCharacter;
UCHAR uCharacterColumn;
UCHAR uCharacterRow;
UCHAR uBit;
WCHAR szInfoText[9];
// Preparations
hBoxDC = CreateCompatibleDC(NULL);
SelectObject(hBoxDC, Info->MainWndInfo->hBoxBmp);
hFont = CreateFontW(13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L"Tahoma");
hOldFont = SelectObject(ps->hdc, hFont);
SetBkMode( ps->hdc, TRANSPARENT );
// What ranges do we have to draw?
uStartRow = ps->rcPaint.top / (CHARACTER_BOX_HEIGHT + CHARACTER_BOX_PADDING);
uEndRow = ps->rcPaint.bottom / (CHARACTER_BOX_HEIGHT + CHARACTER_BOX_PADDING);
uStartColumn = ps->rcPaint.left / (CHARACTER_BOX_WIDTH + CHARACTER_BOX_PADDING);
uEndColumn = ps->rcPaint.right / (CHARACTER_BOX_WIDTH + CHARACTER_BOX_PADDING);
for(uFontRow = uStartRow; uFontRow <= uEndRow; uFontRow++)
{
for(uFontColumn = uStartColumn; uFontColumn <= uEndColumn; uFontColumn++)
{
GetCharacterRect(uFontRow, uFontColumn, &CharacterRect);
uCharacter = uFontRow * 16 + uFontColumn;
// Draw the Character Info Box (header)
BitBlt(ps->hdc,
CharacterRect.left,
CharacterRect.top,
CHARACTER_BOX_WIDTH,
CHARACTER_INFO_BOX_HEIGHT,
hBoxDC,
0,
0,
SRCCOPY);
// Draw the header text
wsprintfW(szInfoText, L"%02u = %02X", uCharacter, uCharacter);
DrawTextW( ps->hdc, szInfoText, -1, &CharacterRect, DT_CENTER );
// Draw the Character Bitmap Box (rectangle with the actual character)
if(Info->uSelectedCharacter == uCharacter)
{
clBackground = RGB(255, 255, 0);
hBrush = CreateSolidBrush(clBackground);
hOldBrush = SelectObject(ps->hdc, hBrush);
}
else
{
clBackground = RGB(255, 255, 255);
SelectObject( ps->hdc, GetStockObject(WHITE_BRUSH) );
}
Rectangle(ps->hdc,
CharacterRect.left,
CharacterRect.top + CHARACTER_INFO_BOX_HEIGHT,
CharacterRect.right,
CharacterRect.bottom);
// Draw the actual character into the box
for(uCharacterRow = 0; uCharacterRow < 8; uCharacterRow++)
{
for(uCharacterColumn = 0; uCharacterColumn < 8; uCharacterColumn++)
{
uBit = Info->Font->Bits[uCharacter * 8 + uCharacterRow] << uCharacterColumn & 0x80;
DrawCharacterPixel(ps, uCharacter, uCharacterRow, uCharacterColumn, uBit, clBackground);
}
}
}
}
SelectObject(ps->hdc, hOldFont);
DeleteObject(hFont);
SelectObject(ps->hdc, hOldBrush);
DeleteObject(hBrush);
DeleteDC(hBoxDC);
}
VOID
EditCurrentGlyph(PFONT_WND_INFO FontWndInfo)
{
PEDIT_GLYPH_INFO EditGlyphInfo;
EditGlyphInfo = (PEDIT_GLYPH_INFO) HeapAlloc( hProcessHeap, 0, sizeof(EDIT_GLYPH_INFO) );
EditGlyphInfo->FontWndInfo = FontWndInfo;
EditGlyphInfo->uCharacter = FontWndInfo->uSelectedCharacter;
RtlCopyMemory( EditGlyphInfo->CharacterBits, FontWndInfo->Font->Bits + FontWndInfo->uSelectedCharacter * 8, sizeof(EditGlyphInfo->CharacterBits) );
DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_EDITGLYPH), FontWndInfo->hSelf, EditGlyphDlgProc, (LPARAM)EditGlyphInfo);
}
VOID
CreateFontBoxesWindow(IN PFONT_WND_INFO FontWndInfo)
{
FontWndInfo->hFontBoxesWnd = CreateWindowExW(0,
szFontBoxesWndClass,
0,
WS_CHILD | WS_VISIBLE,
0,
0,
0,
0,
FontWndInfo->hSelf,
NULL,
hInstance,
FontWndInfo);
}
static LRESULT CALLBACK
FontBoxesWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
PFONT_WND_INFO Info;
Info = (PFONT_WND_INFO) GetWindowLongW(hwnd, GWLP_USERDATA);
if(Info || uMsg == WM_CREATE)
{
switch(uMsg)
{
case WM_CREATE:
Info = (PFONT_WND_INFO)( ( (LPCREATESTRUCT)lParam )->lpCreateParams );
SetWindowLongW(hwnd, GWLP_USERDATA, (LONG)Info);
// Set a fixed window size
SetWindowPos(hwnd, NULL, 0, 0, FONT_BOXES_WND_WIDTH, FONT_BOXES_WND_HEIGHT, SWP_NOZORDER | SWP_NOMOVE);
return 0;
case WM_DESTROY:
SetWindowLongW(hwnd, GWLP_USERDATA, 0);
return 0;
case WM_KEYDOWN:
switch(wParam)
{
case VK_DOWN:
if(Info->uSelectedCharacter < 239)
SetSelectedCharacter(Info, Info->uSelectedCharacter + 16, NULL);
return 0;
case VK_LEFT:
if(Info->uSelectedCharacter)
SetSelectedCharacter(Info, Info->uSelectedCharacter - 1, NULL);
return 0;
case VK_RETURN:
EditCurrentGlyph(Info);
return 0;
case VK_RIGHT:
if(Info->uSelectedCharacter < 255)
SetSelectedCharacter(Info, Info->uSelectedCharacter + 1, NULL);
return 0;
case VK_UP:
if(Info->uSelectedCharacter > 15)
SetSelectedCharacter(Info, Info->uSelectedCharacter - 16, NULL);
return 0;
}
break;
case WM_LBUTTONDBLCLK:
{
EditCurrentGlyph(Info);
return 0;
}
case WM_LBUTTONDOWN:
{
RECT CharacterRect;
INT iRet;
iRet = FontBoxesHitTest( GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), &CharacterRect );
if(iRet >= 0)
SetSelectedCharacter( Info, (UINT)iRet, &CharacterRect );
return 0;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
DrawProc(Info, &ps);
EndPaint(hwnd, &ps);
return 0;
}
}
}
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
BOOL
InitFontBoxesWndClass(VOID)
{
WNDCLASSW wc = {0,};
wc.lpfnWndProc = FontBoxesWndProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH)( COLOR_BTNFACE + 1 );
wc.lpszClassName = szFontBoxesWndClass;
wc.style = CS_DBLCLKS;
return RegisterClassW(&wc) != 0;
}
VOID
UnInitFontBoxesWndClass(VOID)
{
UnregisterClassW(szFontBoxesWndClass, hInstance);
}