diff --git a/rosapps/devutils/directory.rbuild b/rosapps/devutils/directory.rbuild
index 3d6991d8782..071248a4102 100644
--- a/rosapps/devutils/directory.rbuild
+++ b/rosapps/devutils/directory.rbuild
@@ -20,6 +20,10 @@
+
+
+
+
diff --git a/rosapps/devutils/vgafontedit/aboutdlg.c b/rosapps/devutils/vgafontedit/aboutdlg.c
new file mode 100644
index 00000000000..a1247a5c68f
--- /dev/null
+++ b/rosapps/devutils/vgafontedit/aboutdlg.c
@@ -0,0 +1,31 @@
+/*
+ * PROJECT: ReactOS VGA Font Editor
+ * LICENSE: GNU General Public License Version 2.0 or any later version
+ * FILE: devutils/vgafontedit/aboutdlg.c
+ * PURPOSE: About dialog
+ * COPYRIGHT: Copyright 2008 Colin Finck
+ */
+
+#include "precomp.h"
+
+INT_PTR CALLBACK
+AboutDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ UNREFERENCED_PARAMETER(lParam);
+
+ switch(uMsg)
+ {
+ case WM_COMMAND:
+ if( LOWORD(wParam) == IDCANCEL )
+ {
+ EndDialog(hwnd, 0);
+ return TRUE;
+ }
+ break;
+
+ case WM_INITDIALOG:
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/rosapps/devutils/vgafontedit/customwndclasses.h b/rosapps/devutils/vgafontedit/customwndclasses.h
new file mode 100644
index 00000000000..01f1dc75be9
--- /dev/null
+++ b/rosapps/devutils/vgafontedit/customwndclasses.h
@@ -0,0 +1,15 @@
+/*
+ * PROJECT: ReactOS VGA Font Editor
+ * LICENSE: GNU General Public License Version 2.0 or any later version
+ * FILE: devutils/vgafontedit/customwndclasses.h
+ * PURPOSE: Header for custom defined window classes (needed by "precomp.h" and the resource files)
+ * COPYRIGHT: Copyright 2008 Colin Finck
+ */
+
+#ifndef __CUSTOMWNDCLASSES_H
+#define __CUSTOMWNDCLASSES_H
+
+#define EDIT_GLYPH_EDIT_CLASSW L"VGAFontEditEditGlyphEditClass"
+#define EDIT_GLYPH_PREVIEW_CLASSW L"VGAFontEditEditGlyphPreviewClass"
+
+#endif
diff --git a/rosapps/devutils/vgafontedit/editglyphdlg.c b/rosapps/devutils/vgafontedit/editglyphdlg.c
new file mode 100644
index 00000000000..09daa0f24e7
--- /dev/null
+++ b/rosapps/devutils/vgafontedit/editglyphdlg.c
@@ -0,0 +1,297 @@
+/*
+ * PROJECT: ReactOS VGA Font Editor
+ * LICENSE: GNU General Public License Version 2.0 or any later version
+ * FILE: devutils/vgafontedit/editglyphdlg.c
+ * PURPOSE: Dialog for editing a glyph
+ * COPYRIGHT: Copyright 2008 Colin Finck
+ */
+
+#include "precomp.h"
+
+static VOID
+AddToolboxButton(IN HWND hToolbar, IN INT iBitmap, IN INT idCommand, IN BYTE fsState)
+{
+ TBBUTTON tbb = {0,};
+
+ tbb.fsState = fsState;
+ tbb.fsStyle = BTNS_CHECKGROUP;
+ tbb.iBitmap = iBitmap;
+ tbb.idCommand = idCommand;
+
+ SendMessageW( hToolbar, TB_ADDBUTTONSW, 1, (LPARAM)&tbb );
+}
+
+static VOID
+InitToolbox(IN PEDIT_GLYPH_INFO Info)
+{
+ HWND hToolbar;
+ INT iBitmap;
+ TBADDBITMAP tbab;
+
+ hToolbar = GetDlgItem(Info->hSelf, IDC_EDIT_GLYPH_TOOLBOX);
+
+ // Identify the used Common Controls version
+ SendMessageW(hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
+
+ // Set the button size to 24x24
+ SendMessageW( hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(24, 24) );
+ SendMessageW( hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(24, 24) );
+
+ // Add the Toolbox bitmaps
+ tbab.hInst = hInstance;
+ tbab.nID = IDB_EDIT_GLYPH_TOOLBOX;
+ iBitmap = SendMessageW(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
+
+ AddToolboxButton(hToolbar, iBitmap + TOOLBOX_PEN, ID_TOOLBOX_PEN, TBSTATE_ENABLED | TBSTATE_CHECKED);
+}
+
+static VOID
+GetBitRect(IN PEDIT_GLYPH_INFO Info, IN UINT uRow, IN UINT uColumn, OUT LPRECT BitRect)
+{
+ BitRect->left = uColumn * Info->lEditSpacing + 1;
+ BitRect->top = uRow * Info->lEditSpacing + 1;
+ BitRect->right = BitRect->left + Info->lEditSpacing - 1;
+ BitRect->bottom = BitRect->top + Info->lEditSpacing - 1;
+}
+
+static VOID
+SetPixelBit(IN PEDIT_GLYPH_INFO Info, IN UINT uRow, IN UINT uColumn, IN BOOL uBit)
+{
+ // Set the bit in the bitfield
+ if(uBit)
+ Info->CharacterBits[uRow] |= 1 << (7 - uColumn);
+ else
+ Info->CharacterBits[uRow] &= ~( 1 << (7 - uColumn) );
+
+ // Redraw everything
+ InvalidateRect(Info->hEdit, NULL, FALSE);
+ InvalidateRect(Info->hPreview, NULL, FALSE);
+}
+
+static BOOL
+EditGlyphCommand(IN INT idCommand, IN PEDIT_GLYPH_INFO Info)
+{
+ switch(idCommand)
+ {
+ case IDOK:
+ {
+ RECT rect;
+ UINT uColumn;
+ UINT uRow;
+
+ RtlCopyMemory( Info->FontWndInfo->Font->Bits + Info->uCharacter * 8, Info->CharacterBits, sizeof(Info->CharacterBits) );
+
+ GetCharacterPosition(Info->uCharacter, &uRow, &uColumn);
+ GetCharacterRect(uRow, uColumn, &rect);
+ InvalidateRect(Info->FontWndInfo->hFontBoxesWnd, &rect, FALSE);
+
+ Info->FontWndInfo->OpenInfo->bModified = TRUE;
+
+ // Fall through
+ }
+
+ case IDCANCEL:
+ EndDialog(Info->hSelf, 0);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+INT_PTR CALLBACK
+EditGlyphDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ PEDIT_GLYPH_INFO Info;
+
+ Info = (PEDIT_GLYPH_INFO) GetWindowLongW(hwnd, GWLP_USERDATA);
+
+ if(Info || uMsg == WM_INITDIALOG)
+ {
+ switch(uMsg)
+ {
+ case WM_COMMAND:
+ return EditGlyphCommand( LOWORD(wParam), Info );
+
+ case WM_DESTROY:
+ SetWindowLongW(hwnd, GWLP_USERDATA, 0);
+ SetWindowLongW(Info->hEdit, GWLP_USERDATA, 0);
+ SetWindowLongW(Info->hPreview, GWLP_USERDATA, 0 );
+
+ HeapFree(hProcessHeap, 0, Info);
+ return TRUE;
+
+ case WM_INITDIALOG:
+ Info = (PEDIT_GLYPH_INFO) lParam;
+ Info->hSelf = hwnd;
+ Info->hEdit = GetDlgItem(hwnd, IDC_EDIT_GLYPH_EDIT);
+ Info->hPreview = GetDlgItem(hwnd, IDC_EDIT_GLYPH_PREVIEW);
+
+ SetWindowLongW(hwnd, GWLP_USERDATA, (LONG)Info);
+ SetWindowLongW(Info->hEdit, GWLP_USERDATA, (LONG)Info);
+ SetWindowLongW(Info->hPreview, GWLP_USERDATA, (LONG)Info);
+
+ InitToolbox(Info);
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static LRESULT CALLBACK
+EditGlyphEditWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ PEDIT_GLYPH_INFO Info;
+
+ Info = (PEDIT_GLYPH_INFO) GetWindowLongW(hwnd, GWLP_USERDATA);
+
+ if(Info)
+ {
+ switch(uMsg)
+ {
+ case WM_CREATE:
+ return 0;
+
+ case WM_LBUTTONDOWN:
+ SetPixelBit(Info, GET_Y_LPARAM(lParam) / Info->lEditSpacing, GET_X_LPARAM(lParam) / Info->lEditSpacing, 1);
+ return 0;
+
+ case WM_RBUTTONDOWN:
+ SetPixelBit(Info, GET_Y_LPARAM(lParam) / Info->lEditSpacing, GET_X_LPARAM(lParam) / Info->lEditSpacing, 0);
+ return 0;
+
+ case WM_PAINT:
+ {
+ BOOL bBit;
+ HPEN hOldPen;
+ HPEN hPen;
+ PAINTSTRUCT ps;
+ RECT rect;
+ UINT i;
+ UINT j;
+
+ BeginPaint(hwnd, &ps);
+
+ // Draw the grid
+ GetClientRect(hwnd, &rect);
+ Info->lEditSpacing = rect.right / 8;
+
+ hPen = CreatePen( PS_SOLID, 1, RGB(128, 128, 128) );
+ hOldPen = SelectObject(ps.hdc, hPen);
+
+ for(i = 1; i < 8; i++)
+ {
+ MoveToEx(ps.hdc, i * Info->lEditSpacing, 0, NULL);
+ LineTo (ps.hdc, i * Info->lEditSpacing, rect.right);
+
+ MoveToEx(ps.hdc, 0, i * Info->lEditSpacing, NULL);
+ LineTo (ps.hdc, rect.right, i * Info->lEditSpacing);
+ }
+
+ SelectObject(ps.hdc, hOldPen);
+ DeleteObject(hPen);
+
+ // Draw all bits
+ for(i = 0; i < 8; i++)
+ {
+ for(j = 0; j < 8; j++)
+ {
+ bBit = (BOOL) (Info->CharacterBits[i] << j & 0x80);
+
+ GetBitRect(Info, i, j, &rect);
+ FillRect( ps.hdc, &rect, (HBRUSH) GetStockObject(bBit ? BLACK_BRUSH : WHITE_BRUSH) );
+ }
+ }
+
+ // Draw the bounding rectangle
+ SelectObject( ps.hdc, GetStockObject(NULL_BRUSH) );
+ Rectangle(ps.hdc, 0, 0, rect.right, rect.right);
+
+ EndPaint(hwnd, &ps);
+ return 0;
+ }
+ }
+ }
+
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+}
+
+static LRESULT CALLBACK
+EditGlyphPreviewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ PEDIT_GLYPH_INFO Info;
+
+ Info = (PEDIT_GLYPH_INFO) GetWindowLongW(hwnd, GWLP_USERDATA);
+
+ if(Info)
+ {
+ switch(uMsg)
+ {
+ case WM_CREATE:
+ return 0;
+
+ case WM_PAINT:
+ {
+ BOOL bBit;
+ INT iLeft;
+ INT iTop;
+ PAINTSTRUCT ps;
+ RECT rect;
+ UINT i;
+ UINT j;
+
+ BeginPaint(hwnd, &ps);
+
+ // Draw the bounding rectangle
+ GetClientRect(hwnd, &rect);
+ Rectangle(ps.hdc, 0, 0, rect.right, rect.bottom);
+
+ // Draw all bits
+ iLeft = rect.right / 2 - 8 / 2;
+ iTop = rect.bottom / 2 - 8 / 2;
+
+ for(i = 0; i < 8; i++)
+ {
+ for(j = 0; j < 8; j++)
+ {
+ bBit = (BOOL) (Info->CharacterBits[i] << j & 0x80);
+ SetPixel( ps.hdc, j + iLeft, i + iTop, (bBit ? 0 : 0xFFFFFF) );
+ }
+ }
+
+ EndPaint(hwnd, &ps);
+
+ return 0;
+ }
+ }
+ }
+
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+}
+
+BOOL
+InitEditGlyphWndClasses(VOID)
+{
+ WNDCLASSW wc = {0,};
+
+ wc.lpfnWndProc = EditGlyphEditWndProc;
+ wc.hInstance = hInstance;
+ wc.hCursor = LoadCursor( NULL, IDC_ARROW );
+ wc.lpszClassName = EDIT_GLYPH_EDIT_CLASSW;
+
+ if( !RegisterClassW(&wc) )
+ return FALSE;
+
+ wc.lpfnWndProc = EditGlyphPreviewWndProc;
+ wc.lpszClassName = EDIT_GLYPH_PREVIEW_CLASSW;
+
+ return RegisterClassW(&wc) != 0;
+}
+
+VOID
+UnInitEditGlyphWndClasses(VOID)
+{
+ UnregisterClassW(EDIT_GLYPH_EDIT_CLASSW, hInstance);
+ UnregisterClassW(EDIT_GLYPH_PREVIEW_CLASSW, hInstance);
+}
diff --git a/rosapps/devutils/vgafontedit/fileformats.txt b/rosapps/devutils/vgafontedit/fileformats.txt
new file mode 100644
index 00000000000..5294982699d
--- /dev/null
+++ b/rosapps/devutils/vgafontedit/fileformats.txt
@@ -0,0 +1,55 @@
+VGA Font File Formats
+=====================
+
+We only deal with 8x8 fonts with 256 characters, so different formats aren't described here.
+
+1. The binary format (*.bin)
+----------------------------
+A binary font file is always 2048 bytes in size.
+These bytes are divided into 256 characters, so every character is 8 bytes large.
+Each byte represents a character row. Consequently, each column is represented by one bit. The most-significant bit contains the pixel of the first column from the left.
+
+Example:
+ We want to get the pixel in the third column of the second row of the seventh character.
+ We assume you loaded the binary font file completely into a byte array called FontBits.
+
+ // All indexes need to be zero-based
+ UINT uCharacter = 6;
+ UINT uRow = 1;
+ UINT uColumn = 2;
+
+ UCHAR uBit;
+
+ // uBit will either contain 0 (0-bit is set) or 128 dec, 0x80 hex (1-bit is set) now
+ uBit = FontBits[uCharacter * 8 + uRow] << uColumn & 0x80;
+
+2. The PC Screen Font Version 1 format (*.psf)
+----------------------------------------------
+A PC Screen Font Version 1 file is always 2052 bytes in size.
+
+It has the following structure:
+
+struct PSF1_FILE
+{
+ UCHAR uMagic[2];
+ UCHAR uMode;
+ UCHAR uCharSize;
+
+ UCHAR FontBits[2048];
+};
+
+* uMagic contains two magic bytes, which identify a PSFv1 file. These are:
+ uMagic[0] = 0x36
+ uMagic[1] = 0x04
+
+* uMode specifies special modes of the font.
+ We only deal with fonts here, which don't have any special modes, so this value should be 0.
+
+* uCharSize specifies the size of a character.
+ In our case, this needs to be 8.
+
+* Finally the FontBits array contains the font bits in the same format as described above.
+ This way, it is very easy to convert a PSFv1 file to a binary *.bin file.
+
+
+- Colin Finck, 2008/02/01
\ No newline at end of file
diff --git a/rosapps/devutils/vgafontedit/fontboxeswnd.c b/rosapps/devutils/vgafontedit/fontboxeswnd.c
new file mode 100644
index 00000000000..9457ae2cd22
--- /dev/null
+++ b/rosapps/devutils/vgafontedit/fontboxeswnd.c
@@ -0,0 +1,325 @@
+/*
+ * 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
+ */
+
+#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);
+}
diff --git a/rosapps/devutils/vgafontedit/fontwnd.c b/rosapps/devutils/vgafontedit/fontwnd.c
new file mode 100644
index 00000000000..2a91fc8df76
--- /dev/null
+++ b/rosapps/devutils/vgafontedit/fontwnd.c
@@ -0,0 +1,438 @@
+/*
+ * PROJECT: ReactOS VGA Font Editor
+ * LICENSE: GNU General Public License Version 2.0 or any later version
+ * FILE: devutils/vgafontedit/fontwnd.c
+ * PURPOSE: Implements the MDI child window for a font
+ * COPYRIGHT: Copyright 2008 Colin Finck
+ */
+
+#include "precomp.h"
+
+static const WCHAR szFontWndClass[] = L"VGAFontEditFontWndClass";
+
+static BOOL
+InitFont(IN PFONT_WND_INFO Info)
+{
+ Info->Font = (PBITMAP_FONT) HeapAlloc( hProcessHeap, 0, sizeof(BITMAP_FONT) );
+
+ if(Info->OpenInfo->bCreateNew)
+ {
+ ZeroMemory( Info->Font, sizeof(BITMAP_FONT) );
+ return TRUE;
+ }
+ else
+ {
+ // Load a font
+ BOOL bRet = FALSE;
+ DWORD dwTemp;
+ HANDLE hFile;
+
+ hFile = CreateFileW(Info->OpenInfo->pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ LocalizedError( IDS_OPENERROR, GetLastError() );
+ return FALSE;
+ }
+
+ // Let's first check the file size to determine the file type
+ dwTemp = GetFileSize(hFile, NULL);
+
+ switch(dwTemp)
+ {
+ case 2048:
+ // It should be a binary font file
+ Info->OpenInfo->bBinaryFileOpened = TRUE;
+
+ if( ReadFile(hFile, Info->Font, sizeof(BITMAP_FONT), &dwTemp, NULL) )
+ bRet = TRUE;
+ else
+ LocalizedError( IDS_READERROR, GetLastError() );
+
+ break;
+
+ case 2052:
+ {
+ PSF1_HEADER Header;
+
+ // Probably it's a PSFv1 file, check the header to make sure
+ if( !ReadFile(hFile, &Header, sizeof(PSF1_HEADER) , &dwTemp, NULL) )
+ {
+ LocalizedError( IDS_READERROR, GetLastError() );
+ break;
+ }
+ else
+ {
+ if(Header.uMagic[0] == PSF1_MAGIC0 && Header.uMagic[1] == PSF1_MAGIC1)
+ {
+ // Yes, it is a PSFv1 file.
+ // Check the mode and character size. We only support 8x8 fonts with no special mode.
+ if(Header.uCharSize == 8 && Header.uMode == 0)
+ {
+ // Perfect! The file pointer is already set correctly, so we can just read the font bitmap now.
+ if( ReadFile(hFile, Info->Font, sizeof(BITMAP_FONT), &dwTemp, NULL) )
+ bRet = TRUE;
+ else
+ LocalizedError( IDS_READERROR, GetLastError() );
+ }
+ else
+ LocalizedError(IDS_UNSUPPORTEDPSF);
+
+ break;
+ }
+
+ // Fall through if the magic numbers aren't there
+ }
+ }
+
+ default:
+ LocalizedError(IDS_UNSUPPORTEDFORMAT);
+ }
+
+ CloseHandle(hFile);
+ return bRet;
+ }
+}
+
+static LRESULT CALLBACK
+FontWndProc(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_CHILDACTIVATE:
+ Info->MainWndInfo->CurrentFontWnd = Info;
+ SetToolbarFileButtonState(Info->MainWndInfo, TRUE);
+ break;
+
+ case WM_CREATE:
+ Info = (PFONT_WND_INFO)( ( (LPMDICREATESTRUCT) ( (LPCREATESTRUCT)lParam )->lpCreateParams )->lParam );
+ Info->hSelf = hwnd;
+
+ SetWindowLongW(hwnd, GWLP_USERDATA, (LONG)Info);
+
+ CreateFontBoxesWindow(Info);
+
+ return 0;
+
+ case WM_USER_APPCLOSE:
+ case WM_CLOSE:
+ if(Info->OpenInfo->bModified)
+ {
+ INT nMsgBoxResult;
+ PWSTR pszPrompt;
+ WCHAR szFile[MAX_PATH];
+
+ GetWindowTextW(hwnd, szFile, MAX_PATH);
+ LoadAndFormatString(IDS_SAVEPROMPT, &pszPrompt, szFile);
+
+ nMsgBoxResult = MessageBoxW(hwnd, pszPrompt, szAppName, MB_YESNOCANCEL | MB_ICONQUESTION);
+ HeapFree(hProcessHeap, 0, pszPrompt);
+
+ switch(nMsgBoxResult)
+ {
+ case IDYES:
+ DoFileSave(Info->MainWndInfo, FALSE);
+ break;
+
+ case IDCANCEL:
+ // 0 = Stop the process of closing the windows (same value for both WM_CLOSE and WM_USER_APPCLOSE)
+ return 0;
+
+ // IDNO is handled automatically
+ }
+ }
+
+ // If there is another child, it will undo the following actions through its WM_CHILDACTIVATE handler.
+ // Otherwise CurrentFontWnd will stay NULL, so the main window knows that no more childs are opened.
+ Info->MainWndInfo->CurrentFontWnd = NULL;
+ SetToolbarFileButtonState(Info->MainWndInfo, FALSE);
+
+ if(uMsg == WM_USER_APPCLOSE)
+ {
+ // First do the tasks we would do for a normal WM_CLOSE message, then return the value for WM_USER_APPCLOSE
+ // Anything other than 0 indicates that the application shall continue closing the windows
+ DefMDIChildProcW(hwnd, WM_CLOSE, 0, 0);
+ return 1;
+ }
+ break;
+
+ case WM_DESTROY:
+ // Remove the window from the linked list
+ if(Info->MainWndInfo->FirstFontWnd == Info)
+ {
+ Info->MainWndInfo->FirstFontWnd = Info->NextFontWnd;
+
+ if(Info->NextFontWnd)
+ Info->NextFontWnd->PrevFontWnd = NULL;
+ }
+ else
+ Info->PrevFontWnd->NextFontWnd = Info->NextFontWnd;
+
+ if(Info->MainWndInfo->LastFontWnd == Info)
+ {
+ Info->MainWndInfo->LastFontWnd = Info->PrevFontWnd;
+
+ if(Info->PrevFontWnd)
+ Info->PrevFontWnd->NextFontWnd = NULL;
+ }
+ else
+ Info->NextFontWnd->PrevFontWnd = Info->PrevFontWnd;
+
+ // Free memory
+ if(Info->Font)
+ HeapFree(hProcessHeap, 0, Info->Font);
+
+ if(Info->OpenInfo->pszFileName)
+ HeapFree(hProcessHeap, 0, Info->OpenInfo->pszFileName);
+
+ HeapFree(hProcessHeap, 0, Info->OpenInfo);
+ HeapFree(hProcessHeap, 0, Info);
+
+ SetWindowLongW(hwnd, GWLP_USERDATA, 0);
+ return 0;
+
+ case WM_SETFOCUS:
+ // Set the keyboard focus to the FontBoxes window every time the Font window gets the focus
+ SetFocus(Info->hFontBoxesWnd);
+ break;
+
+ case WM_SIZE:
+ {
+ INT nHeight = HIWORD(lParam);
+ INT nWidth = LOWORD(lParam);
+ POINT pt;
+ RECT WndRect;
+
+ // This ugly workaround is necessary for not setting either the Height or the Width of the window with SetWindowPos
+ GetWindowRect(Info->hFontBoxesWnd, &WndRect);
+ pt.x = WndRect.left;
+ pt.y = WndRect.top;
+ ScreenToClient(hwnd, &pt);
+
+ if(nHeight < FONT_BOXES_WND_HEIGHT)
+ {
+ SCROLLINFO si;
+
+ // Set the vertical scroll bar
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_RANGE | SIF_PAGE;
+ si.nMin = 0;
+ si.nMax = FONT_BOXES_WND_HEIGHT;
+ si.nPage = nHeight;
+ SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+ }
+ else
+ {
+ ShowScrollBar(hwnd, SB_VERT, FALSE);
+
+ // Store the new y coordinate in pt.y as well (needed for the SetWindowPos call for setting a new x coordinate)
+ pt.y = nHeight / 2 - FONT_BOXES_WND_HEIGHT / 2;
+ SetWindowPos(Info->hFontBoxesWnd,
+ NULL,
+ pt.x,
+ pt.y,
+ 0,
+ 0,
+ SWP_NOSIZE | SWP_NOZORDER);
+ }
+
+ if(nWidth < FONT_BOXES_WND_WIDTH)
+ {
+ SCROLLINFO si;
+
+ // Set the horizontal scroll bar
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_RANGE | SIF_PAGE;
+ si.nMin = 0;
+ si.nMax = FONT_BOXES_WND_WIDTH;
+ si.nPage = nWidth;
+ SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
+ }
+ else
+ {
+ ShowScrollBar(hwnd, SB_HORZ, FALSE);
+
+ SetWindowPos(Info->hFontBoxesWnd,
+ NULL,
+ nWidth / 2 - FONT_BOXES_WND_WIDTH / 2,
+ pt.y,
+ 0,
+ 0,
+ SWP_NOSIZE | SWP_NOZORDER);
+ }
+
+ // We have to call DefMDIChildProcW here as well, otherwise we won't get the Minimize/Maximize/Close buttons for a maximized MDI child.
+ break;
+ }
+
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ {
+ INT nBar;
+ INT nOrgPos;
+ SCROLLINFO si;
+
+ if(uMsg == WM_HSCROLL)
+ nBar = SB_HORZ;
+ else
+ nBar = SB_VERT;
+
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_ALL;
+ GetScrollInfo(hwnd, nBar, &si);
+
+ nOrgPos = si.nPos;
+
+ switch( LOWORD(wParam) )
+ {
+ // Constant is the same as SB_LEFT for WM_HSCROLL
+ case SB_TOP:
+ si.nPos = si.nMin;
+ break;
+
+ // Constant is the same as SB_RIGHT for WM_HSCROLL
+ case SB_BOTTOM:
+ si.nPos = si.nMax;
+ break;
+
+ // Constant is the same as SB_LINELEFT for WM_HSCROLL
+ case SB_LINEUP:
+ si.nPos -= 20;
+ break;
+
+ // Constant is the same as SB_LINERIGHT for WM_HSCROLL
+ case SB_LINEDOWN:
+ si.nPos += 20;
+ break;
+
+ // Constant is the same as SB_PAGELEFT for WM_HSCROLL
+ case SB_PAGEUP:
+ si.nPos -= si.nPage;
+ break;
+
+ // Constant is the same as SB_PAGERIGHT for WM_HSCROLL
+ case SB_PAGEDOWN:
+ si.nPos += si.nPage;
+ break;
+
+ case SB_THUMBTRACK:
+ si.nPos = si.nTrackPos;
+ break;
+ }
+
+ si.fMask = SIF_POS;
+ SetScrollInfo(hwnd, nBar, &si, TRUE);
+ GetScrollInfo(hwnd, nBar, &si);
+
+ if(si.nPos != nOrgPos)
+ {
+ // This ugly workaround is necessary for not setting the x coordinate
+ POINT pt;
+ RECT WndRect;
+
+ GetWindowRect(Info->hFontBoxesWnd, &WndRect);
+ pt.x = WndRect.left;
+ pt.y = WndRect.top;
+ ScreenToClient(hwnd, &pt);
+
+ if(uMsg == WM_HSCROLL)
+ SetWindowPos(Info->hFontBoxesWnd, NULL, -si.nPos, pt.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
+ else
+ SetWindowPos(Info->hFontBoxesWnd, NULL, pt.x, -si.nPos, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
+ }
+
+ return 0;
+ }
+ }
+ }
+
+ return DefMDIChildProcW(hwnd, uMsg, wParam, lParam);
+}
+
+BOOL
+CreateFontWindow(IN PMAIN_WND_INFO MainWndInfo, IN PFONT_OPEN_INFO OpenInfo)
+{
+ HWND hFontWnd;
+ PFONT_WND_INFO Info;
+
+ Info = (PFONT_WND_INFO) HeapAlloc( hProcessHeap, HEAP_ZERO_MEMORY, sizeof(FONT_WND_INFO) );
+
+ if(Info)
+ {
+ Info->MainWndInfo = MainWndInfo;
+ Info->OpenInfo = OpenInfo;
+
+ if( InitFont(Info) )
+ {
+ PWSTR pszWindowTitle;
+
+ if(OpenInfo->pszFileName)
+ pszWindowTitle = wcsrchr(OpenInfo->pszFileName, '\\') + 1;
+ else
+ LoadAndFormatString(IDS_DOCNAME, &pszWindowTitle, ++MainWndInfo->uDocumentCounter);
+
+ hFontWnd = CreateMDIWindowW( szFontWndClass,
+ pszWindowTitle,
+ 0,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ FONT_WND_MIN_WIDTH,
+ FONT_WND_MIN_HEIGHT,
+ MainWndInfo->hMdiClient,
+ hInstance,
+ (LPARAM)Info );
+
+ if(!OpenInfo->pszFileName)
+ HeapFree(hProcessHeap, 0, pszWindowTitle);
+
+ if(hFontWnd)
+ {
+ // Add the new window to the linked list
+ if(Info->MainWndInfo->LastFontWnd)
+ {
+ Info->PrevFontWnd = Info->MainWndInfo->LastFontWnd;
+ Info->PrevFontWnd->NextFontWnd = Info;
+ Info->MainWndInfo->LastFontWnd = Info;
+ }
+ else
+ {
+ Info->MainWndInfo->FirstFontWnd = Info;
+ Info->MainWndInfo->LastFontWnd = Info;
+ }
+
+ return TRUE;
+ }
+ }
+
+ HeapFree(hProcessHeap, 0, Info);
+ }
+
+ return FALSE;
+}
+
+BOOL
+InitFontWndClass(VOID)
+{
+ WNDCLASSW wc = {0,};
+
+ wc.lpfnWndProc = FontWndProc;
+ wc.hInstance = hInstance;
+ wc.hCursor = LoadCursor( NULL, IDC_ARROW );
+ wc.hIcon = LoadIconW( hInstance, MAKEINTRESOURCEW(IDI_DOC) );
+ wc.hbrBackground = (HBRUSH)( COLOR_BTNFACE + 1 );
+ wc.lpszClassName = szFontWndClass;
+
+ return RegisterClassW(&wc) != 0;
+}
+
+VOID
+UnInitFontWndClass(VOID)
+{
+ UnregisterClassW(szFontWndClass, hInstance);
+}
diff --git a/rosapps/devutils/vgafontedit/lang/en-US.rc b/rosapps/devutils/vgafontedit/lang/en-US.rc
new file mode 100644
index 00000000000..83f7a3cf8ee
--- /dev/null
+++ b/rosapps/devutils/vgafontedit/lang/en-US.rc
@@ -0,0 +1,82 @@
+/*
+ * PROJECT: ReactOS VGA Font Editor
+ * LICENSE: GNU General Public License Version 2.0 or any later version
+ * FILE: devutils/vgafontedit/lang/en-US.rc
+ * PURPOSE: English resource file
+ * COPYRIGHT: Copyright 2008 Colin Finck
+ * TRANSLATOR: Colin Finck
+ */
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+IDD_ABOUT DIALOGEX 10, 10, 130, 62
+STYLE DS_SHELLFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+CAPTION "About"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ ICON IDI_MAIN, IDC_STATIC, 10, 10, 20, 20
+ LTEXT "ReactOS VGA Font Editor", IDC_STATIC, 37, 10, 93, 10
+ LTEXT "Copyright 2008 Colin Finck", IDC_STATIC, 37, 20, 93, 10
+ DEFPUSHBUTTON "OK", IDCANCEL, 40, 44, 55, 15
+END
+
+IDD_EDITGLYPH DIALOGEX 10, 10, 246, 197
+STYLE DS_SHELLFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Edit Glyph"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "", IDC_EDIT_GLYPH_TOOLBOX, TOOLBARCLASSNAMEA, CCS_NODIVIDER | CCS_NORESIZE, 5, 5, 24, 82
+ CONTROL "", IDC_EDIT_GLYPH_EDIT, EDIT_GLYPH_EDIT_CLASSW, 0, 39, 5, 160, 160
+ CONTROL "", IDC_EDIT_GLYPH_PREVIEW, EDIT_GLYPH_PREVIEW_CLASSW, 0, 209, 5, 32, 32
+
+ DEFPUSHBUTTON "OK", IDOK, 48, 177, 70, 14
+ PUSHBUTTON "Cancel", IDCANCEL, 125, 177, 70, 14
+END
+
+IDM_MAINMENU MENU
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&New\tCtrl+N", ID_FILE_NEW
+ MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN
+ MENUITEM "Close", ID_FILE_CLOSE
+ MENUITEM SEPARATOR
+ MENUITEM "Save\tCtrl+S", ID_FILE_SAVE
+ MENUITEM "Save As...", ID_FILE_SAVE_AS
+ MENUITEM SEPARATOR
+ MENUITEM "Exit\tAlt+F4", ID_FILE_EXIT
+ END
+
+ POPUP "&Window"
+ BEGIN
+ MENUITEM "&Cascade", ID_WINDOW_CASCADE
+ MENUITEM "Tile &Horizontally", ID_WINDOW_TILE_HORZ
+ MENUITEM "Tile &Vertically", ID_WINDOW_TILE_VERT
+ MENUITEM "&Arrange Icons", ID_WINDOW_ARRANGE
+ MENUITEM SEPARATOR
+ MENUITEM "Nex&t\tCtrl+F6", ID_WINDOW_NEXT
+ END
+
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&About...", ID_HELP_ABOUT
+ END
+END
+
+STRINGTABLE
+BEGIN
+ IDS_OPENFILTER, "All supported formats (*.bin,*.psf)|*.bin;*.psf|Binary Font Files (*.bin)|*.bin|PC Screen Fonts Version 1 (*.psf)|*.psf|"
+ IDS_SAVEFILTER, "Binary Font Files (*.bin)|*.bin|"
+ IDS_OPENERROR, "Error while opening the file! (Error number %1!u!)"
+ IDS_READERROR, "Error while reading the file! (Error number %1!u!)"
+ IDS_WRITEERROR, "Error while writing the file! (Error number %1!u!)"
+ IDS_UNSUPPORTEDFORMAT, "Unsupported file format!"
+ IDS_UNSUPPORTEDPSF, "Unsupported PSF font format! The editor only supports 8x8 fonts with no special modes."
+ IDS_DOCNAME, "Font %1!u!"
+ IDS_SAVEPROMPT, "The file ""%1"" was modified, but not saved.\n\nDo you want to save it?"
+
+ IDS_TOOLTIP_NEW, "New"
+ IDS_TOOLTIP_OPEN, "Open"
+ IDS_TOOLTIP_SAVE, "Save"
+ IDS_TOOLTIP_EDIT_GLYPH, "Edit Glyph"
+END
diff --git a/rosapps/devutils/vgafontedit/main.c b/rosapps/devutils/vgafontedit/main.c
new file mode 100644
index 00000000000..c9438114815
--- /dev/null
+++ b/rosapps/devutils/vgafontedit/main.c
@@ -0,0 +1,57 @@
+/*
+ * PROJECT: ReactOS VGA Font Editor
+ * LICENSE: GNU General Public License Version 2.0 or any later version
+ * FILE: devutils/vgafontedit/main.c
+ * PURPOSE: Main entry point of the application
+ * COPYRIGHT: Copyright 2008 Colin Finck
+ */
+
+#include "precomp.h"
+
+const WCHAR szAppName[] = L"ReactOS VGA Font Editor";
+
+HINSTANCE hInstance;
+HANDLE hProcessHeap;
+
+INT WINAPI
+wWinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
+{
+ HACCEL hAccel;
+ INT nRet = 1;
+ MSG msg;
+ PMAIN_WND_INFO Info = 0;
+
+ UNREFERENCED_PARAMETER(hPrevInstance);
+ UNREFERENCED_PARAMETER(lpCmdLine);
+
+ hInstance = hInst;
+ hProcessHeap = GetProcessHeap();
+
+ hAccel = LoadAcceleratorsW( hInstance, MAKEINTRESOURCEW(IDA_MAINACCELERATORS) );
+
+ if( InitMainWndClass() && InitFontWndClass() && InitFontBoxesWndClass() && InitEditGlyphWndClasses() )
+ {
+ if( CreateMainWindow(nCmdShow, &Info) )
+ {
+ while( GetMessageW(&msg, NULL, 0, 0) )
+ {
+ if( !TranslateMDISysAccel(Info->hMdiClient, &msg) &&
+ !TranslateAccelerator(Info->hMainWnd, hAccel, &msg) )
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ nRet = 0;
+ }
+ }
+
+ // Just unregister our window classes, don't care whether they were created or not
+ UnInitEditGlyphWndClasses();
+ UnInitFontBoxesWndClass();
+ UnInitFontWndClass();
+ UnInitMainWndClass();
+
+ return nRet;
+}
diff --git a/rosapps/devutils/vgafontedit/main.rc b/rosapps/devutils/vgafontedit/main.rc
new file mode 100644
index 00000000000..61276cbcdb6
--- /dev/null
+++ b/rosapps/devutils/vgafontedit/main.rc
@@ -0,0 +1,32 @@
+/*
+ * PROJECT: ReactOS VGA Font Editor
+ * LICENSE: GNU General Public License Version 2.0 or any later version
+ * FILE: devutils/vgafontedit/main.rc
+ * PURPOSE: Main resource file
+ * COPYRIGHT: Copyright 2008 Colin Finck
+ */
+
+#include
+#include
+#include "resource.h"
+#include "customwndclasses.h"
+
+#define REACTOS_STR_FILE_DESCRIPTION "ReactOS VGA Font Editor"
+#define REACTOS_STR_INTERNAL_NAME "vgafontedit"
+#define REACTOS_STR_ORIGINAL_FILENAME "vgafontedit.exe"
+#include
+
+IDA_MAINACCELERATORS ACCELERATORS
+BEGIN
+ "N", ID_FILE_NEW, VIRTKEY, CONTROL
+ "O", ID_FILE_OPEN, VIRTKEY, CONTROL
+ "S", ID_FILE_SAVE, VIRTKEY, CONTROL
+END
+
+IDB_MAIN_TOOLBAR BITMAP "res/toolbar.bmp"
+IDB_EDIT_GLYPH_TOOLBOX BITMAP "res/toolbox.bmp"
+IDI_MAIN ICON "res/main.ico"
+IDI_DOC ICON "res/doc.ico"
+
+// Languages
+#include "lang/en-US.rc"
diff --git a/rosapps/devutils/vgafontedit/mainwnd.c b/rosapps/devutils/vgafontedit/mainwnd.c
new file mode 100644
index 00000000000..2c50fb526eb
--- /dev/null
+++ b/rosapps/devutils/vgafontedit/mainwnd.c
@@ -0,0 +1,477 @@
+/*
+ * PROJECT: ReactOS VGA Font Editor
+ * LICENSE: GNU General Public License Version 2.0 or any later version
+ * FILE: devutils/vgafontedit/mainwnd.c
+ * PURPOSE: Implements the main window of the application
+ * COPYRIGHT: Copyright 2008 Colin Finck
+ */
+
+#include "precomp.h"
+
+static const WCHAR szMainWndClass[] = L"VGAFontEditMainWndClass";
+
+static VOID
+InitResources(IN PMAIN_WND_INFO Info)
+{
+ HDC hMemDC;
+ HDC hMainDC;
+ HPEN hPen;
+ RECT rect;
+
+ hMemDC = CreateCompatibleDC(NULL);
+ hMainDC = GetDC(Info->hMainWnd);
+
+ // Create the "Box" bitmap
+ Info->hBoxBmp = CreateCompatibleBitmap(hMainDC, CHARACTER_BOX_WIDTH, CHARACTER_BOX_HEIGHT);
+ SelectObject(hMemDC, Info->hBoxBmp);
+
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = CHARACTER_INFO_BOX_WIDTH;
+ rect.bottom = CHARACTER_INFO_BOX_HEIGHT;
+ FillRect( hMemDC, &rect, (HBRUSH)(COLOR_BTNFACE + 1) );
+
+ SelectObject( hMemDC, GetStockObject(WHITE_PEN) );
+ Rectangle(hMemDC, 0, 0, CHARACTER_INFO_BOX_WIDTH - 1, 2);
+ Rectangle(hMemDC, 0, 2, 2, CHARACTER_INFO_BOX_HEIGHT - 1);
+
+ hPen = CreatePen( PS_SOLID, 1, RGB(128, 128, 128) );
+ SelectObject(hMemDC, hPen);
+ Rectangle(hMemDC, 1, CHARACTER_INFO_BOX_HEIGHT - 2, CHARACTER_INFO_BOX_WIDTH, CHARACTER_INFO_BOX_HEIGHT);
+ Rectangle(hMemDC, CHARACTER_INFO_BOX_WIDTH - 2, 1, CHARACTER_INFO_BOX_WIDTH, CHARACTER_INFO_BOX_HEIGHT - 2);
+
+ SetPixel( hMemDC, CHARACTER_INFO_BOX_WIDTH - 1, 0, RGB(128, 128, 128) );
+ SetPixel( hMemDC, 0, CHARACTER_INFO_BOX_HEIGHT - 1, RGB(128, 128, 128) );
+
+ DeleteObject(hPen);
+ DeleteDC(hMemDC);
+}
+
+static VOID
+UnInitResources(IN PMAIN_WND_INFO Info)
+{
+ DeleteObject(Info->hBoxBmp);
+}
+
+static VOID
+AddToolbarButton(IN PMAIN_WND_INFO Info, IN INT iBitmap, IN INT idCommand, IN UINT uID)
+{
+ PWSTR pszTooltip;
+ TBBUTTON tbb = {0,};
+
+ if( AllocAndLoadString(&pszTooltip, uID) )
+ {
+ tbb.fsState = TBSTATE_ENABLED;
+ tbb.iBitmap = iBitmap;
+ tbb.idCommand = idCommand;
+ tbb.iString = (INT_PTR)pszTooltip;
+
+ SendMessageW( Info->hToolbar, TB_ADDBUTTONSW, 1, (LPARAM)&tbb );
+ HeapFree(hProcessHeap, 0, pszTooltip);
+ }
+}
+
+static VOID
+SetToolbarButtonState(IN PMAIN_WND_INFO Info, INT idCommand, BOOL bEnabled)
+{
+ TBBUTTONINFOW tbbi = {0,};
+
+ tbbi.cbSize = sizeof(tbbi);
+ tbbi.dwMask = TBIF_STATE;
+ tbbi.fsState = (bEnabled ? TBSTATE_ENABLED : 0);
+
+ SendMessageW(Info->hToolbar, TB_SETBUTTONINFOW, idCommand, (LPARAM)&tbbi);
+}
+
+VOID
+SetToolbarFileButtonState(IN PMAIN_WND_INFO Info, BOOL bEnabled)
+{
+ SetToolbarButtonState(Info, ID_FILE_SAVE, bEnabled);
+ SetToolbarButtonState(Info, ID_EDIT_GLYPH, bEnabled);
+}
+
+static VOID
+AddToolbarSeparator(IN PMAIN_WND_INFO Info)
+{
+ TBBUTTON tbb = {0,};
+
+ tbb.fsStyle = BTNS_SEP;
+
+ SendMessageW( Info->hToolbar, TB_ADDBUTTONSW, 1, (LPARAM)&tbb );
+}
+
+static VOID
+InitMainWnd(IN PMAIN_WND_INFO Info)
+{
+ CLIENTCREATESTRUCT ccs;
+ INT iCustomBitmaps;
+ INT iStandardBitmaps;
+ TBADDBITMAP tbab;
+
+ // Add the toolbar
+ Info->hToolbar = CreateWindowExW(0,
+ TOOLBARCLASSNAMEW,
+ NULL,
+ WS_VISIBLE | WS_CHILD | TBSTYLE_TOOLTIPS,
+ 0,
+ 0,
+ 0,
+ 0,
+ Info->hMainWnd,
+ NULL,
+ hInstance,
+ NULL);
+
+ // Identify the used Common Controls version
+ SendMessageW(Info->hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
+
+ // Enable Tooltips
+ SendMessageW(Info->hToolbar, TB_SETMAXTEXTROWS, 0, 0);
+
+ // Add the toolbar bitmaps
+ tbab.hInst = HINST_COMMCTRL;
+ tbab.nID = IDB_STD_SMALL_COLOR;
+ iStandardBitmaps = SendMessageW(Info->hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
+
+ tbab.hInst = hInstance;
+ tbab.nID = IDB_MAIN_TOOLBAR;
+ iCustomBitmaps = SendMessageW(Info->hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
+
+ // Add the toolbar buttons
+ AddToolbarButton(Info, iStandardBitmaps + STD_FILENEW, ID_FILE_NEW, IDS_TOOLTIP_NEW);
+ AddToolbarButton(Info, iStandardBitmaps + STD_FILEOPEN, ID_FILE_OPEN, IDS_TOOLTIP_OPEN);
+ AddToolbarButton(Info, iStandardBitmaps + STD_FILESAVE, ID_FILE_SAVE, IDS_TOOLTIP_SAVE);
+ AddToolbarSeparator(Info);
+ AddToolbarButton(Info, iCustomBitmaps + TOOLBAR_EDIT_GLYPH, ID_EDIT_GLYPH, IDS_TOOLTIP_EDIT_GLYPH);
+
+ SetToolbarFileButtonState(Info, FALSE);
+
+ // Add the MDI client area
+ ccs.hWindowMenu = GetSubMenu(Info->hMenu, 1);
+ ccs.idFirstChild = ID_MDI_FIRSTCHILD;
+
+ Info->hMdiClient = CreateWindowExW(WS_EX_CLIENTEDGE,
+ L"MDICLIENT",
+ NULL,
+ WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL,
+ 0,
+ 0,
+ 0,
+ 0,
+ Info->hMainWnd,
+ NULL,
+ hInstance,
+ &ccs);
+
+ // Initialize the file handling
+ FileInitialize(Info->hMainWnd);
+}
+
+static VOID
+InitMenuPopup(IN PMAIN_WND_INFO Info)
+{
+ UINT uState;
+
+ uState = MF_BYCOMMAND | (Info->CurrentFontWnd == NULL);
+
+ EnableMenuItem(Info->hMenu, ID_FILE_CLOSE, uState);
+ EnableMenuItem(Info->hMenu, ID_FILE_SAVE, uState);
+ EnableMenuItem(Info->hMenu, ID_FILE_SAVE_AS, uState);
+}
+
+static VOID
+DoFileNew(IN PMAIN_WND_INFO Info)
+{
+ PFONT_OPEN_INFO OpenInfo;
+
+ OpenInfo = (PFONT_OPEN_INFO) HeapAlloc( hProcessHeap, HEAP_ZERO_MEMORY, sizeof(FONT_OPEN_INFO) );
+ OpenInfo->bCreateNew = TRUE;
+
+ CreateFontWindow(Info, OpenInfo);
+}
+
+static VOID
+DoFileOpen(IN PMAIN_WND_INFO Info)
+{
+ PFONT_OPEN_INFO OpenInfo;
+
+ OpenInfo = (PFONT_OPEN_INFO) HeapAlloc( hProcessHeap, HEAP_ZERO_MEMORY, sizeof(FONT_OPEN_INFO) );
+ OpenInfo->pszFileName = HeapAlloc(hProcessHeap, 0, MAX_PATH);
+ OpenInfo->pszFileName[0] = 0;
+
+ if( DoOpenFile(OpenInfo->pszFileName) )
+ {
+ OpenInfo->bCreateNew = FALSE;
+ CreateFontWindow(Info, OpenInfo);
+ }
+}
+
+VOID
+DoFileSave(IN PMAIN_WND_INFO Info, IN BOOL bSaveAs)
+{
+ DWORD dwBytesWritten;
+ HANDLE hFile;
+
+ // Show the "Save" dialog
+ // - if "Save As" was clicked
+ // - if the file was not yet saved
+ // - if another format than the binary format was opened
+ if(bSaveAs || !Info->CurrentFontWnd->OpenInfo->bBinaryFileOpened)
+ {
+ if(!Info->CurrentFontWnd->OpenInfo->pszFileName)
+ {
+ Info->CurrentFontWnd->OpenInfo->pszFileName = (PWSTR) HeapAlloc(hProcessHeap, 0, MAX_PATH);
+ Info->CurrentFontWnd->OpenInfo->pszFileName[0] = 0;
+ }
+ else if(!Info->CurrentFontWnd->OpenInfo->bBinaryFileOpened)
+ {
+ // For a file in another format, the user has to enter a new file name as well
+ Info->CurrentFontWnd->OpenInfo->pszFileName[0] = 0;
+ }
+
+ if( !DoSaveFile(Info->CurrentFontWnd->OpenInfo->pszFileName) )
+ return;
+ }
+
+ // Save the binary font
+ hFile = CreateFileW(Info->CurrentFontWnd->OpenInfo->pszFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ LocalizedError( IDS_OPENERROR, GetLastError() );
+ return;
+ }
+
+ if( !WriteFile(hFile, Info->CurrentFontWnd->Font, sizeof(BITMAP_FONT), &dwBytesWritten, NULL) )
+ LocalizedError( IDS_WRITEERROR, GetLastError() );
+
+ CloseHandle(hFile);
+}
+
+static BOOL
+MenuCommand(IN INT nMenuItemID, IN PMAIN_WND_INFO Info)
+{
+ switch(nMenuItemID)
+ {
+ // File Menu
+ case ID_FILE_NEW:
+ DoFileNew(Info);
+ return TRUE;
+
+ case ID_FILE_OPEN:
+ DoFileOpen(Info);
+ return TRUE;
+
+ case ID_FILE_CLOSE:
+ SendMessageW(Info->CurrentFontWnd->hSelf, WM_CLOSE, 0, 0);
+ return TRUE;
+
+ case ID_FILE_SAVE:
+ DoFileSave(Info, FALSE);
+ return TRUE;
+
+ case ID_FILE_SAVE_AS:
+ DoFileSave(Info, TRUE);
+ return TRUE;
+
+ case ID_FILE_EXIT:
+ PostMessage(Info->hMainWnd, WM_CLOSE, 0, 0);
+ return TRUE;
+
+ // "Edit Glyph" toolbar button
+ case ID_EDIT_GLYPH:
+ EditCurrentGlyph(Info->CurrentFontWnd);
+ return TRUE;
+
+ // Window Menu
+ case ID_WINDOW_TILE_HORZ:
+ SendMessageW(Info->hMdiClient, WM_MDITILE, MDITILE_HORIZONTAL, 0);
+ return TRUE;
+
+ case ID_WINDOW_TILE_VERT:
+ SendMessageW(Info->hMdiClient, WM_MDITILE, MDITILE_VERTICAL, 0);
+ return TRUE;
+
+ case ID_WINDOW_CASCADE:
+ SendMessageW(Info->hMdiClient, WM_MDICASCADE, 0, 0);
+ return TRUE;
+
+ case ID_WINDOW_ARRANGE:
+ SendMessageW(Info->hMdiClient, WM_MDIICONARRANGE, 0, 0);
+ return TRUE;
+
+ case ID_WINDOW_NEXT:
+ SendMessageW(Info->hMdiClient, WM_MDINEXT, 0, 0);
+ return TRUE;
+
+ // Help Menu
+ case ID_HELP_ABOUT:
+ DialogBoxW( hInstance, MAKEINTRESOURCEW(IDD_ABOUT), Info->hMainWnd, AboutDlgProc );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static VOID
+MainWndSize(PMAIN_WND_INFO Info, INT cx, INT cy)
+{
+ HDWP dwp;
+ INT iMdiTop;
+ RECT ToolbarRect;
+
+ iMdiTop = 0;
+
+ dwp = BeginDeferWindowPos(2);
+ if(!dwp)
+ return;
+
+ if(Info->hToolbar)
+ {
+ GetWindowRect(Info->hToolbar, &ToolbarRect);
+ iMdiTop += ToolbarRect.bottom - ToolbarRect.top;
+
+ dwp = DeferWindowPos(dwp, Info->hToolbar, NULL, 0, 0, cx, ToolbarRect.bottom - ToolbarRect.top, SWP_NOZORDER);
+ if(!dwp)
+ return;
+ }
+
+ if(Info->hMdiClient)
+ {
+ dwp = DeferWindowPos(dwp, Info->hMdiClient, NULL, 0, iMdiTop, cx, cy - iMdiTop, SWP_NOZORDER);
+ if(!dwp)
+ return;
+ }
+
+ EndDeferWindowPos(dwp);
+}
+
+static LRESULT CALLBACK
+MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ PMAIN_WND_INFO Info;
+
+ Info = (PMAIN_WND_INFO) GetWindowLongW(hwnd, GWLP_USERDATA);
+
+ if(Info || uMsg == WM_CREATE)
+ {
+ switch(uMsg)
+ {
+ case WM_COMMAND:
+ if( MenuCommand( LOWORD(wParam), Info ) )
+ return 0;
+
+ break;
+
+ case WM_CLOSE:
+ if(Info->FirstFontWnd)
+ {
+ // Send WM_CLOSE to all subwindows, so they can prompt for saving unsaved files
+ PFONT_WND_INFO pNextWnd;
+ PFONT_WND_INFO pWnd;
+
+ pWnd = Info->FirstFontWnd;
+
+ do
+ {
+ // The pWnd structure might already be destroyed after the WM_CLOSE, so we have to preserve the address of the next window here
+ pNextWnd = pWnd->NextFontWnd;
+
+ // Send WM_USER_APPCLOSE, so we can check for a custom return value
+ // In this case, we check if the user clicked the "Cancel" button in one of the prompts and if so, we don't close the app
+ if( !SendMessage(pWnd->hSelf, WM_USER_APPCLOSE, 0, 0) )
+ return 0;
+ }
+ while( (pWnd = pNextWnd) );
+ }
+ break;
+
+ case WM_CREATE:
+ Info = (PMAIN_WND_INFO)( ( (LPCREATESTRUCT)lParam )->lpCreateParams );
+ Info->hMainWnd = hwnd;
+ Info->hMenu = GetMenu(hwnd);
+ SetWindowLongW(hwnd, GWLP_USERDATA, (LONG)Info);
+
+ InitMainWnd(Info);
+ InitResources(Info);
+
+ ShowWindow(hwnd, Info->nCmdShow);
+ return 0;
+
+ case WM_DESTROY:
+ UnInitResources(Info);
+
+ HeapFree(hProcessHeap, 0, Info);
+ SetWindowLongW(hwnd, GWLP_USERDATA, 0);
+ PostQuitMessage(0);
+ return 0;
+
+ case WM_INITMENUPOPUP:
+ InitMenuPopup(Info);
+ break;
+
+ case WM_SIZE:
+ MainWndSize( Info, LOWORD(lParam), HIWORD(lParam) );
+ return 0;
+ }
+ }
+
+ if(Info && Info->hMdiClient)
+ return DefFrameProcW(hwnd, Info->hMdiClient, uMsg, wParam, lParam);
+ else
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+}
+
+BOOL
+CreateMainWindow(IN INT nCmdShow, OUT PMAIN_WND_INFO* Info)
+{
+ HWND hMainWnd;
+
+ *Info = (PMAIN_WND_INFO) HeapAlloc( hProcessHeap, HEAP_ZERO_MEMORY, sizeof(MAIN_WND_INFO) );
+
+ if(*Info)
+ {
+ (*Info)->nCmdShow = nCmdShow;
+
+ hMainWnd = CreateWindowExW(0,
+ szMainWndClass,
+ szAppName,
+ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ LoadMenuW(hInstance, MAKEINTRESOURCEW(IDM_MAINMENU)),
+ hInstance,
+ *Info);
+
+ if(hMainWnd)
+ return TRUE;
+ else
+ HeapFree(hProcessHeap, 0, *Info);
+ }
+
+ return FALSE;
+}
+
+BOOL
+InitMainWndClass(VOID)
+{
+ WNDCLASSW wc = {0,};
+
+ wc.lpfnWndProc = MainWndProc;
+ wc.hInstance = hInstance;
+ wc.hCursor = LoadCursor( NULL, IDC_ARROW );
+ wc.hIcon = LoadIconW( hInstance, MAKEINTRESOURCEW(IDI_MAIN) );
+ wc.hbrBackground = (HBRUSH)( COLOR_BTNFACE + 1 );
+ wc.lpszClassName = szMainWndClass;
+
+ return RegisterClassW(&wc) != 0;
+}
+
+VOID
+UnInitMainWndClass(VOID)
+{
+ UnregisterClassW(szMainWndClass, hInstance);
+}
diff --git a/rosapps/devutils/vgafontedit/misc.c b/rosapps/devutils/vgafontedit/misc.c
new file mode 100644
index 00000000000..1d256b75a4b
--- /dev/null
+++ b/rosapps/devutils/vgafontedit/misc.c
@@ -0,0 +1,118 @@
+/*
+ * PROJECT: ReactOS VGA Font Editor
+ * LICENSE: GNU General Public License Version 2.0 only
+ * FILE: devutils/vgafontedit/misc.c
+ * PURPOSE: Some miscellaneous resource functions (copied from "devmgmt") and modified
+ * COPYRIGHT: Copyright 2006 Ged Murphy
+ * Copyright 2008 Colin Finck
+ */
+
+#include "precomp.h"
+
+static INT
+LengthOfStrResource(IN UINT uID)
+{
+ HRSRC hrSrc;
+ HGLOBAL hRes;
+ PWSTR lpName, lpStr;
+
+ /* There are always blocks of 16 strings */
+ lpName = (PWSTR) MAKEINTRESOURCEW((uID >> 4) + 1);
+
+ /* Find the string table block */
+ if ((hrSrc = FindResourceW(hInstance, lpName, (PWSTR)RT_STRING)) != 0 &&
+ (hRes = LoadResource(hInstance, hrSrc)) != 0 &&
+ (lpStr = (PWSTR)LockResource(hRes)) != 0)
+ {
+ UINT x;
+
+ /* Find the string we're looking for */
+ uID &= 0xF; /* position in the block, same as % 16 */
+
+ for (x = 0; x < uID; x++)
+ lpStr += (*lpStr) + 1;
+
+ /* Found the string */
+ return (int)(*lpStr);
+ }
+
+ return -1;
+}
+
+INT
+AllocAndLoadString(OUT PWSTR *lpTarget, IN UINT uID)
+{
+ INT ln;
+
+ ln = LengthOfStrResource(uID);
+
+ if (ln++ > 0)
+ {
+ (*lpTarget) = (PWSTR) HeapAlloc( hProcessHeap, 0, ln * sizeof(WCHAR) );
+
+ if (*lpTarget)
+ {
+ INT nRet;
+
+ nRet = LoadStringW(hInstance, uID, *lpTarget, ln);
+
+ if (!nRet)
+ HeapFree(hProcessHeap, 0, *lpTarget);
+
+ return nRet;
+ }
+ }
+
+ return 0;
+}
+
+static DWORD
+VarListLoadAndFormatString(IN UINT uID, OUT PWSTR *lpTarget, IN va_list* Args)
+{
+ DWORD Ret = 0;
+ PWSTR lpFormat;
+
+ if (AllocAndLoadString(&lpFormat, uID) > 0)
+ {
+ /* let's use FormatMessage to format it because it has the ability to allocate
+ memory automatically */
+ Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
+ lpFormat,
+ 0,
+ 0,
+ (LPWSTR)lpTarget,
+ 0,
+ Args);
+
+ HeapFree(hProcessHeap, 0, lpFormat);
+ }
+
+ return Ret;
+}
+
+DWORD
+LoadAndFormatString(IN UINT uID, OUT PWSTR *lpTarget, ...)
+{
+ DWORD Ret;
+ va_list Args;
+
+ va_start(Args, lpTarget);
+ Ret = VarListLoadAndFormatString(uID, lpTarget, &Args);
+ va_end(Args);
+
+ return Ret;
+}
+
+VOID
+LocalizedError(IN UINT uID, ...)
+{
+ PWSTR pszError;
+ va_list Args;
+
+ va_start(Args, uID);
+ VarListLoadAndFormatString(uID, &pszError, &Args);
+ va_end(Args);
+
+ MessageBoxW(NULL, pszError, szAppName, MB_ICONERROR);
+ HeapFree(hProcessHeap, 0, pszError);
+}
diff --git a/rosapps/devutils/vgafontedit/opensave.c b/rosapps/devutils/vgafontedit/opensave.c
new file mode 100644
index 00000000000..a5c54f71453
--- /dev/null
+++ b/rosapps/devutils/vgafontedit/opensave.c
@@ -0,0 +1,77 @@
+/*
+ * PROJECT: ReactOS VGA Font Editor
+ * LICENSE: GNU General Public License Version 2.0 or any later version
+ * FILE: devutils/vgafontedit/opensave.c
+ * PURPOSE: Functions for opening and saving files
+ * COPYRIGHT: Copyright 2008 Colin Finck
+ */
+
+#include "precomp.h"
+
+static OPENFILENAMEW ofn;
+
+VOID
+FileInitialize(IN HWND hwnd)
+{
+ ZeroMemory( &ofn, sizeof(ofn) );
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = hwnd;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.lpstrDefExt = L"bin";
+}
+
+static __inline VOID
+PrepareFilter(IN PWSTR pszFilter)
+{
+ // RC strings can't be double-null terminated, so we use | instead to separate the entries.
+ // Convert them back to null characters here.
+ do
+ {
+ if(*pszFilter == '|')
+ *pszFilter = 0;
+ }
+ while(*++pszFilter);
+}
+
+BOOL
+DoOpenFile(OUT PWSTR pszFileName)
+{
+ BOOL bRet;
+ PWSTR pszFilter;
+
+ if( AllocAndLoadString(&pszFilter, IDS_OPENFILTER) )
+ {
+ PrepareFilter(pszFilter);
+ ofn.lpstrFilter = pszFilter;
+ ofn.lpstrFile = pszFileName;
+ ofn.Flags = OFN_FILEMUSTEXIST;
+
+ bRet = GetOpenFileNameW(&ofn);
+ HeapFree(hProcessHeap, 0, pszFilter);
+
+ return bRet;
+ }
+
+ return FALSE;
+}
+
+BOOL
+DoSaveFile(IN OUT PWSTR pszFileName)
+{
+ BOOL bRet;
+ PWSTR pszFilter;
+
+ if( AllocAndLoadString(&pszFilter, IDS_SAVEFILTER) )
+ {
+ PrepareFilter(pszFilter);
+ ofn.lpstrFilter = pszFilter;
+ ofn.lpstrFile = pszFileName;
+
+ bRet = GetSaveFileNameW(&ofn);
+ HeapFree(hProcessHeap, 0, pszFilter);
+
+ return bRet;
+ }
+
+ return FALSE;
+}
diff --git a/rosapps/devutils/vgafontedit/precomp.h b/rosapps/devutils/vgafontedit/precomp.h
new file mode 100644
index 00000000000..f2e8ec66e66
--- /dev/null
+++ b/rosapps/devutils/vgafontedit/precomp.h
@@ -0,0 +1,161 @@
+/*
+ * PROJECT: ReactOS VGA Font Editor
+ * LICENSE: GNU General Public License Version 2.0 or any later version
+ * FILE: devutils/vgafontedit/precomp.h
+ * PURPOSE: Main header
+ * COPYRIGHT: Copyright 2008 Colin Finck
+ */
+
+#ifndef __PRECOMP_H
+#define __PRECOMP_H
+
+#include
+#include
+#include
+#include "resource.h"
+#include "customwndclasses.h"
+
+// Forward declarations
+typedef struct _FONT_WND_INFO FONT_WND_INFO, *PFONT_WND_INFO;
+
+// Structure declarations
+typedef struct _BITMAP_FONT
+{
+ UCHAR Bits[2048];
+} BITMAP_FONT, *PBITMAP_FONT;
+
+typedef struct _MAIN_WND_INFO
+{
+ HWND hMainWnd;
+ HWND hMdiClient;
+ HMENU hMenu;
+ HWND hToolbar;
+ INT nCmdShow;
+
+ HBITMAP hBoxBmp;
+ PFONT_WND_INFO CurrentFontWnd;
+ ULONG uDocumentCounter;
+
+ PFONT_WND_INFO FirstFontWnd;
+ PFONT_WND_INFO LastFontWnd;
+} MAIN_WND_INFO, *PMAIN_WND_INFO;
+
+typedef struct _FONT_OPEN_INFO
+{
+ BOOL bCreateNew;
+ BOOL bBinaryFileOpened;
+ BOOL bModified;
+ PWSTR pszFileName;
+} FONT_OPEN_INFO, *PFONT_OPEN_INFO;
+
+struct _FONT_WND_INFO
+{
+ PMAIN_WND_INFO MainWndInfo;
+ PFONT_OPEN_INFO OpenInfo;
+ PBITMAP_FONT Font;
+
+ HWND hSelf;
+ HWND hFontBoxesWnd;
+ UINT uSelectedCharacter;
+
+ PFONT_WND_INFO PrevFontWnd;
+ PFONT_WND_INFO NextFontWnd;
+};
+
+typedef struct _EDIT_GLYPH_INFO
+{
+ PFONT_WND_INFO FontWndInfo;
+
+ UINT uCharacter;
+ UCHAR CharacterBits[8];
+
+ HWND hSelf;
+ HWND hEdit;
+ HWND hPreview;
+ LONG lEditSpacing;
+} EDIT_GLYPH_INFO, *PEDIT_GLYPH_INFO;
+
+#define ID_MDI_FIRSTCHILD 50000
+
+// Dimensions of the visual elements
+#define CHARACTER_INFO_BOX_WIDTH 55
+#define CHARACTER_INFO_BOX_HEIGHT 16
+#define CHARACTER_BITMAP_BOX_HEIGHT 14
+#define CHARACTER_BOX_WIDTH (CHARACTER_INFO_BOX_WIDTH)
+#define CHARACTER_BOX_HEIGHT (CHARACTER_INFO_BOX_HEIGHT + CHARACTER_BITMAP_BOX_HEIGHT)
+#define CHARACTER_BOX_PADDING 5
+#define FONT_BOXES_WND_WIDTH (CHARACTER_BOX_WIDTH * 16 + CHARACTER_BOX_PADDING * 15)
+#define FONT_BOXES_WND_HEIGHT (CHARACTER_BOX_HEIGHT * 16 + CHARACTER_BOX_PADDING * 15)
+#define FONT_WND_MIN_WIDTH (FONT_BOXES_WND_WIDTH + 25)
+#define FONT_WND_MIN_HEIGHT (FONT_BOXES_WND_HEIGHT + GetSystemMetrics(SM_CYCAPTION) + 25)
+
+// Custom return values
+#define HITTEST_SEPARATOR -1
+
+// Custom window messages
+#define WM_USER_APPCLOSE (WM_USER + 1)
+
+// Bitmap numbers
+#define TOOLBAR_EDIT_GLYPH 0
+#define TOOLBOX_PEN 0
+
+// PSFv1 file handling
+#define PSF1_MAGIC0 0x36
+#define PSF1_MAGIC1 0x04
+
+typedef struct _PSF1_HEADER
+{
+ UCHAR uMagic[2];
+ UCHAR uMode;
+ UCHAR uCharSize;
+} PSF1_HEADER, *PPSF1_HEADER;
+
+
+//
+// Function prototypes
+//
+
+// aboutdlg.c
+INT_PTR CALLBACK AboutDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+// editglyphdlg.c
+INT_PTR CALLBACK EditGlyphDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+BOOL InitEditGlyphWndClasses(VOID);
+VOID UnInitEditGlyphWndClasses(VOID);
+
+// fontboxeswnd.c
+VOID CreateFontBoxesWindow(PFONT_WND_INFO FontWndInfo);
+BOOL InitFontBoxesWndClass(VOID);
+VOID UnInitFontBoxesWndClass(VOID);
+VOID GetCharacterRect(IN UINT uFontRow, IN UINT uFontColumn, OUT LPRECT CharacterRect);
+__inline VOID GetCharacterPosition(IN UINT uCharacter, OUT PUINT uFontRow, OUT PUINT uFontColumn);
+VOID EditCurrentGlyph(PFONT_WND_INFO FontWndInfo);
+
+// fontwnd.c
+BOOL CreateFontWindow(PMAIN_WND_INFO MainWndInfo, PFONT_OPEN_INFO OpenInfo);
+BOOL InitFontWndClass(VOID);
+VOID UnInitFontWndClass(VOID);
+
+// main.c
+extern const WCHAR szAppName[];
+extern HINSTANCE hInstance;
+extern HANDLE hProcessHeap;
+
+// mainwnd.c
+BOOL CreateMainWindow(IN INT nCmdShow, OUT PMAIN_WND_INFO* Info);
+BOOL InitMainWndClass(VOID);
+VOID UnInitMainWndClass(VOID);
+VOID DoFileSave(IN PMAIN_WND_INFO Info, IN BOOL bSaveAs);
+VOID SetToolbarFileButtonState(IN PMAIN_WND_INFO Info, BOOL bEnabled);
+
+// misc.c
+INT AllocAndLoadString(OUT PWSTR *lpTarget, IN UINT uID);
+DWORD LoadAndFormatString(IN UINT uID, OUT PWSTR *lpTarget, ...);
+VOID LocalizedError(IN UINT uID, ...);
+
+// opensave.c
+VOID FileInitialize(HWND hwnd);
+BOOL DoOpenFile(OUT PWSTR pszFileName);
+BOOL DoSaveFile(IN PWSTR pszFileName);
+
+#endif
diff --git a/rosapps/devutils/vgafontedit/res/doc.ico b/rosapps/devutils/vgafontedit/res/doc.ico
new file mode 100644
index 00000000000..3c4eaf6e6ac
Binary files /dev/null and b/rosapps/devutils/vgafontedit/res/doc.ico differ
diff --git a/rosapps/devutils/vgafontedit/res/main.ico b/rosapps/devutils/vgafontedit/res/main.ico
new file mode 100644
index 00000000000..bb7ca2bc8b2
Binary files /dev/null and b/rosapps/devutils/vgafontedit/res/main.ico differ
diff --git a/rosapps/devutils/vgafontedit/res/toolbar.bmp b/rosapps/devutils/vgafontedit/res/toolbar.bmp
new file mode 100644
index 00000000000..df58307b34b
Binary files /dev/null and b/rosapps/devutils/vgafontedit/res/toolbar.bmp differ
diff --git a/rosapps/devutils/vgafontedit/res/toolbox.bmp b/rosapps/devutils/vgafontedit/res/toolbox.bmp
new file mode 100644
index 00000000000..481b5e19f54
Binary files /dev/null and b/rosapps/devutils/vgafontedit/res/toolbox.bmp differ
diff --git a/rosapps/devutils/vgafontedit/resource.h b/rosapps/devutils/vgafontedit/resource.h
new file mode 100644
index 00000000000..07d161454d6
--- /dev/null
+++ b/rosapps/devutils/vgafontedit/resource.h
@@ -0,0 +1,73 @@
+/*
+ * PROJECT: ReactOS VGA Font Editor
+ * LICENSE: GNU General Public License Version 2.0 or any later version
+ * FILE: devutils/vgafontedit/resource.h
+ * PURPOSE: Header containing resource IDs
+ * COPYRIGHT: Copyright 2008 Colin Finck
+ */
+
+#ifndef __RESOURCE_H
+#define __RESOURCE_H
+
+#define IDC_STATIC -1
+
+// Icons
+#define IDI_MAIN 100
+#define IDI_DOC 101
+
+// Accelerator Tables
+#define IDA_MAINACCELERATORS 201
+
+// Menus
+#define IDM_MAINMENU 301
+
+// Bitmaps
+#define IDB_MAIN_TOOLBAR 401
+#define IDB_EDIT_GLYPH_TOOLBOX 402
+
+// Dialogs
+#define IDD_ABOUT 501
+#define IDD_EDITGLYPH 502
+
+// Dialog Controls
+#define IDC_EDIT_GLYPH_TOOLBOX 601
+#define IDC_EDIT_GLYPH_EDIT 602
+#define IDC_EDIT_GLYPH_PREVIEW 603
+
+// Command IDs
+#define ID_FILE_NEW 1001
+#define ID_FILE_OPEN 1002
+#define ID_FILE_CLOSE 1003
+#define ID_FILE_SAVE 1004
+#define ID_FILE_SAVE_AS 1005
+#define ID_FILE_EXIT 1006
+
+#define ID_EDIT_GLYPH 2001
+
+#define ID_WINDOW_TILE_HORZ 3001
+#define ID_WINDOW_TILE_VERT 3002
+#define ID_WINDOW_CASCADE 3003
+#define ID_WINDOW_NEXT 3004
+#define ID_WINDOW_ARRANGE 3005
+
+#define ID_HELP_ABOUT 4001
+
+#define ID_TOOLBOX_PEN 5001
+
+// Strings
+#define IDS_OPENFILTER 10001
+#define IDS_SAVEFILTER 10002
+#define IDS_OPENERROR 10003
+#define IDS_READERROR 10004
+#define IDS_WRITEERROR 10005
+#define IDS_UNSUPPORTEDFORMAT 10006
+#define IDS_UNSUPPORTEDPSF 10007
+#define IDS_DOCNAME 10008
+#define IDS_SAVEPROMPT 10009
+
+#define IDS_TOOLTIP_NEW 11001
+#define IDS_TOOLTIP_OPEN 11002
+#define IDS_TOOLTIP_SAVE 11003
+#define IDS_TOOLTIP_EDIT_GLYPH 11004
+
+#endif
diff --git a/rosapps/devutils/vgafontedit/vgafontedit.rbuild b/rosapps/devutils/vgafontedit/vgafontedit.rbuild
new file mode 100644
index 00000000000..fe4d77dccf4
--- /dev/null
+++ b/rosapps/devutils/vgafontedit/vgafontedit.rbuild
@@ -0,0 +1,19 @@
+
+ .
+
+ kernel32
+ user32
+ gdi32
+ comdlg32
+
+ aboutdlg.c
+ editglyphdlg.c
+ fontboxeswnd.c
+ fontwnd.c
+ main.c
+ main.rc
+ mainwnd.c
+ misc.c
+ opensave.c
+ precomp.h
+