2 * PROJECT: ReactOS VGA Font Editor
3 * LICENSE: GNU General Public License Version 2.0 or any later version
4 * FILE: devutils/vgafontedit/fontboxeswnd.c
5 * PURPOSE: Implements the window showing the character boxes for a font
6 * COPYRIGHT: Copyright 2008 Colin Finck <mail@colinfinck.de>
11 static const WCHAR szFontBoxesWndClass
[] = L
"VGAFontEditFontBoxesWndClass";
14 DrawCharacterPixel(IN PAINTSTRUCT
*ps
, IN UINT uCharacter
, IN UCHAR uRow
, IN UCHAR uColumn
, IN UCHAR uBit
, IN COLORREF clBackground
)
19 x
= (uCharacter
% 16) * (CHARACTER_BOX_WIDTH
+ CHARACTER_BOX_PADDING
) + 24 + uColumn
;
20 y
= (uCharacter
/ 16) * (CHARACTER_BOX_HEIGHT
+ CHARACTER_BOX_PADDING
)+ 1 + CHARACTER_INFO_BOX_HEIGHT
+ 2 + uRow
;
22 SetPixel( ps
->hdc
, x
, y
, (uBit
? 0 : clBackground
) );
26 GetCharacterRect(IN UINT uFontRow
, IN UINT uFontColumn
, OUT LPRECT CharacterRect
)
28 CharacterRect
->left
= uFontColumn
* (CHARACTER_BOX_WIDTH
+ CHARACTER_BOX_PADDING
);
29 CharacterRect
->top
= uFontRow
* (CHARACTER_BOX_HEIGHT
+ CHARACTER_BOX_PADDING
);
30 CharacterRect
->right
= CharacterRect
->left
+ CHARACTER_BOX_WIDTH
;
31 CharacterRect
->bottom
= CharacterRect
->top
+ CHARACTER_BOX_HEIGHT
;
35 GetCharacterPosition(IN UINT uCharacter
, OUT PUINT uFontRow
, OUT PUINT uFontColumn
)
37 *uFontRow
= uCharacter
/ 16;
38 *uFontColumn
= uCharacter
% 16;
42 FontBoxesHitTest(IN UINT xPos
, IN UINT yPos
, OUT LPRECT CharacterRect
)
47 uFontColumn
= xPos
/ (CHARACTER_BOX_WIDTH
+ CHARACTER_BOX_PADDING
);
48 uFontRow
= yPos
/ (CHARACTER_BOX_HEIGHT
+ CHARACTER_BOX_PADDING
);
49 GetCharacterRect(uFontRow
, uFontColumn
, CharacterRect
);
51 if(xPos
> (UINT
)CharacterRect
->right
|| yPos
> (UINT
)CharacterRect
->bottom
)
52 // The user clicked on separator space, so return HITTEST_SEPARATOR
53 return HITTEST_SEPARATOR
;
55 // Return the character number
56 return (uFontRow
* 16 + uFontColumn
);
60 SetSelectedCharacter(IN PFONT_WND_INFO Info
, IN UINT uNewCharacter
, OPTIONAL IN LPRECT NewCharacterRect
)
62 LPRECT pCharacterRect
;
63 RECT OldCharacterRect
;
67 // Remove the selection of the old character
68 GetCharacterPosition(Info
->uSelectedCharacter
, &uFontRow
, &uFontColumn
);
69 GetCharacterRect(uFontRow
, uFontColumn
, &OldCharacterRect
);
70 InvalidateRect(Info
->hFontBoxesWnd
, &OldCharacterRect
, FALSE
);
72 // You may pass the RECT of the new character, otherwise we'll allocate memory for one and get it ourselves
74 pCharacterRect
= NewCharacterRect
;
77 GetCharacterPosition(uNewCharacter
, &uFontRow
, &uFontColumn
);
78 pCharacterRect
= (LPRECT
) HeapAlloc( hProcessHeap
, 0, sizeof(RECT
) );
79 GetCharacterRect(uFontRow
, uFontColumn
, pCharacterRect
);
82 // Select the new character
83 Info
->uSelectedCharacter
= uNewCharacter
;
84 InvalidateRect(Info
->hFontBoxesWnd
, pCharacterRect
, FALSE
);
87 HeapFree(hProcessHeap
, 0, pCharacterRect
);
91 DrawProc(IN PFONT_WND_INFO Info
, IN PAINTSTRUCT
* ps
)
93 COLORREF clBackground
;
107 UCHAR uCharacterColumn
;
114 hBoxDC
= CreateCompatibleDC(NULL
);
115 hBitmapOld
= SelectObject(hBoxDC
, Info
->MainWndInfo
->hBoxBmp
);
117 hFont
= CreateFontW(13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L
"Tahoma");
118 hOldFont
= SelectObject(ps
->hdc
, hFont
);
120 SetBkMode( ps
->hdc
, TRANSPARENT
);
122 // What ranges do we have to draw?
123 uStartRow
= ps
->rcPaint
.top
/ (CHARACTER_BOX_HEIGHT
+ CHARACTER_BOX_PADDING
);
124 uEndRow
= ps
->rcPaint
.bottom
/ (CHARACTER_BOX_HEIGHT
+ CHARACTER_BOX_PADDING
);
125 uStartColumn
= ps
->rcPaint
.left
/ (CHARACTER_BOX_WIDTH
+ CHARACTER_BOX_PADDING
);
126 uEndColumn
= ps
->rcPaint
.right
/ (CHARACTER_BOX_WIDTH
+ CHARACTER_BOX_PADDING
);
128 for(uFontRow
= uStartRow
; uFontRow
<= uEndRow
; uFontRow
++)
130 for(uFontColumn
= uStartColumn
; uFontColumn
<= uEndColumn
; uFontColumn
++)
132 GetCharacterRect(uFontRow
, uFontColumn
, &CharacterRect
);
133 uCharacter
= uFontRow
* 16 + uFontColumn
;
135 // Draw the Character Info Box (header)
140 CHARACTER_INFO_BOX_HEIGHT
,
146 // Draw the header text
147 wsprintfW(szInfoText
, L
"%02u = %02X", uCharacter
, uCharacter
);
148 DrawTextW( ps
->hdc
, szInfoText
, -1, &CharacterRect
, DT_CENTER
);
150 // Draw the Character Bitmap Box (rectangle with the actual character)
151 if(Info
->uSelectedCharacter
== uCharacter
)
153 clBackground
= RGB(255, 255, 0);
154 hBrush
= CreateSolidBrush(clBackground
);
155 hOldBrush
= SelectObject(ps
->hdc
, hBrush
);
159 clBackground
= RGB(255, 255, 255);
160 SelectObject( ps
->hdc
, GetStockObject(WHITE_BRUSH
) );
165 CharacterRect
.top
+ CHARACTER_INFO_BOX_HEIGHT
,
167 CharacterRect
.bottom
);
169 // Draw the actual character into the box
170 for(uCharacterRow
= 0; uCharacterRow
< 8; uCharacterRow
++)
172 for(uCharacterColumn
= 0; uCharacterColumn
< 8; uCharacterColumn
++)
174 uBit
= Info
->Font
->Bits
[uCharacter
* 8 + uCharacterRow
] << uCharacterColumn
& 0x80;
175 DrawCharacterPixel(ps
, uCharacter
, uCharacterRow
, uCharacterColumn
, uBit
, clBackground
);
181 SelectObject(hBoxDC
, hBitmapOld
);
182 SelectObject(ps
->hdc
, hOldFont
);
184 SelectObject(ps
->hdc
, hOldBrush
);
185 DeleteObject(hBrush
);
190 EditCurrentGlyph(PFONT_WND_INFO FontWndInfo
)
192 PEDIT_GLYPH_INFO EditGlyphInfo
;
194 // Has the window for this character already been opened?
195 EditGlyphInfo
= FontWndInfo
->FirstEditGlyphWnd
;
199 if(EditGlyphInfo
->uCharacter
== FontWndInfo
->uSelectedCharacter
)
201 // Yes, it has. Bring it to the front.
202 SetFocus(EditGlyphInfo
->hSelf
);
206 EditGlyphInfo
= EditGlyphInfo
->NextEditGlyphWnd
;
209 // No. Then create a new one
210 EditGlyphInfo
= (PEDIT_GLYPH_INFO
) HeapAlloc( hProcessHeap
, 0, sizeof(EDIT_GLYPH_INFO
) );
211 EditGlyphInfo
->FontWndInfo
= FontWndInfo
;
212 EditGlyphInfo
->uCharacter
= FontWndInfo
->uSelectedCharacter
;
213 RtlCopyMemory( EditGlyphInfo
->CharacterBits
, FontWndInfo
->Font
->Bits
+ FontWndInfo
->uSelectedCharacter
* 8, sizeof(EditGlyphInfo
->CharacterBits
) );
215 // Add the new window to the linked list
216 EditGlyphInfo
->PrevEditGlyphWnd
= FontWndInfo
->LastEditGlyphWnd
;
217 EditGlyphInfo
->NextEditGlyphWnd
= NULL
;
219 if(FontWndInfo
->LastEditGlyphWnd
)
220 FontWndInfo
->LastEditGlyphWnd
->NextEditGlyphWnd
= EditGlyphInfo
;
222 FontWndInfo
->FirstEditGlyphWnd
= EditGlyphInfo
;
224 FontWndInfo
->LastEditGlyphWnd
= EditGlyphInfo
;
226 // Open the window as a modeless dialog, so people can edit several characters at the same time.
227 EditGlyphInfo
->hSelf
= CreateDialogParamW(hInstance
, MAKEINTRESOURCEW(IDD_EDITGLYPH
), FontWndInfo
->hSelf
, EditGlyphDlgProc
, (LPARAM
)EditGlyphInfo
);
228 ShowWindow(EditGlyphInfo
->hSelf
, SW_SHOW
);
232 CreateFontBoxesWindow(IN PFONT_WND_INFO FontWndInfo
)
234 FontWndInfo
->hFontBoxesWnd
= CreateWindowExW(0,
237 WS_CHILD
| WS_VISIBLE
,
248 static LRESULT CALLBACK
249 FontBoxesWndProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
253 Info
= (PFONT_WND_INFO
) GetWindowLongW(hwnd
, GWLP_USERDATA
);
255 if(Info
|| uMsg
== WM_CREATE
)
260 Info
= (PFONT_WND_INFO
)( ( (LPCREATESTRUCT
)lParam
)->lpCreateParams
);
261 SetWindowLongW(hwnd
, GWLP_USERDATA
, (LONG
)Info
);
263 // Set a fixed window size
264 SetWindowPos(hwnd
, NULL
, 0, 0, FONT_BOXES_WND_WIDTH
, FONT_BOXES_WND_HEIGHT
, SWP_NOZORDER
| SWP_NOMOVE
);
269 SetWindowLongW(hwnd
, GWLP_USERDATA
, 0);
276 if(Info
->uSelectedCharacter
< 239)
277 SetSelectedCharacter(Info
, Info
->uSelectedCharacter
+ 16, NULL
);
281 if(Info
->uSelectedCharacter
)
282 SetSelectedCharacter(Info
, Info
->uSelectedCharacter
- 1, NULL
);
286 EditCurrentGlyph(Info
);
290 if(Info
->uSelectedCharacter
< 255)
291 SetSelectedCharacter(Info
, Info
->uSelectedCharacter
+ 1, NULL
);
295 if(Info
->uSelectedCharacter
> 15)
296 SetSelectedCharacter(Info
, Info
->uSelectedCharacter
- 16, NULL
);
302 case WM_LBUTTONDBLCLK
:
304 EditCurrentGlyph(Info
);
313 iRet
= FontBoxesHitTest( GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
), &CharacterRect
);
316 SetSelectedCharacter( Info
, (UINT
)iRet
, &CharacterRect
);
325 BeginPaint(hwnd
, &ps
);
334 return DefWindowProcW(hwnd
, uMsg
, wParam
, lParam
);
338 InitFontBoxesWndClass(VOID
)
342 wc
.lpfnWndProc
= FontBoxesWndProc
;
343 wc
.hInstance
= hInstance
;
344 wc
.hCursor
= LoadCursor( NULL
, IDC_ARROW
);
345 wc
.hbrBackground
= (HBRUSH
)( COLOR_BTNFACE
+ 1 );
346 wc
.lpszClassName
= szFontBoxesWndClass
;
347 wc
.style
= CS_DBLCLKS
;
349 return RegisterClassW(&wc
) != 0;
353 UnInitFontBoxesWndClass(VOID
)
355 UnregisterClassW(szFontBoxesWndClass
, hInstance
);