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 +