2 * PROJECT: ReactOS VGA Font Editor
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Implements the window showing the character boxes for a font
5 * COPYRIGHT: Copyright 2008 Colin Finck (colin@reactos.org)
10 static const WCHAR szFontBoxesWndClass
[] = L
"VGAFontEditFontBoxesWndClass";
13 DrawCharacterPixel(IN PAINTSTRUCT
*ps
, IN UINT uCharacter
, IN UCHAR uRow
, IN UCHAR uColumn
, IN UCHAR uBit
, IN COLORREF clBackground
)
18 x
= (uCharacter
% 16) * (CHARACTER_BOX_WIDTH
+ CHARACTER_BOX_PADDING
) + 24 + uColumn
;
19 y
= (uCharacter
/ 16) * (CHARACTER_BOX_HEIGHT
+ CHARACTER_BOX_PADDING
)+ 1 + CHARACTER_INFO_BOX_HEIGHT
+ 2 + uRow
;
21 SetPixel( ps
->hdc
, x
, y
, (uBit
? 0 : clBackground
) );
25 GetCharacterRect(IN UINT uFontRow
, IN UINT uFontColumn
, OUT LPRECT CharacterRect
)
27 CharacterRect
->left
= uFontColumn
* (CHARACTER_BOX_WIDTH
+ CHARACTER_BOX_PADDING
);
28 CharacterRect
->top
= uFontRow
* (CHARACTER_BOX_HEIGHT
+ CHARACTER_BOX_PADDING
);
29 CharacterRect
->right
= CharacterRect
->left
+ CHARACTER_BOX_WIDTH
;
30 CharacterRect
->bottom
= CharacterRect
->top
+ CHARACTER_BOX_HEIGHT
;
34 GetCharacterPosition(IN UINT uCharacter
, OUT PUINT uFontRow
, OUT PUINT uFontColumn
)
36 *uFontRow
= uCharacter
/ 16;
37 *uFontColumn
= uCharacter
% 16;
41 FontBoxesHitTest(IN UINT xPos
, IN UINT yPos
, OUT LPRECT CharacterRect
)
46 uFontColumn
= xPos
/ (CHARACTER_BOX_WIDTH
+ CHARACTER_BOX_PADDING
);
47 uFontRow
= yPos
/ (CHARACTER_BOX_HEIGHT
+ CHARACTER_BOX_PADDING
);
48 GetCharacterRect(uFontRow
, uFontColumn
, CharacterRect
);
50 if(xPos
> (UINT
)CharacterRect
->right
|| yPos
> (UINT
)CharacterRect
->bottom
)
51 // The user clicked on separator space, so return HITTEST_SEPARATOR
52 return HITTEST_SEPARATOR
;
54 // Return the character number
55 return (uFontRow
* 16 + uFontColumn
);
59 SetSelectedCharacter(IN PFONT_WND_INFO Info
, IN UINT uNewCharacter
, OPTIONAL IN LPRECT NewCharacterRect
)
61 LPRECT pCharacterRect
;
62 RECT OldCharacterRect
;
66 // Remove the selection of the old character
67 GetCharacterPosition(Info
->uSelectedCharacter
, &uFontRow
, &uFontColumn
);
68 GetCharacterRect(uFontRow
, uFontColumn
, &OldCharacterRect
);
69 InvalidateRect(Info
->hFontBoxesWnd
, &OldCharacterRect
, FALSE
);
71 // You may pass the RECT of the new character, otherwise we'll allocate memory for one and get it ourselves
73 pCharacterRect
= NewCharacterRect
;
76 GetCharacterPosition(uNewCharacter
, &uFontRow
, &uFontColumn
);
77 pCharacterRect
= (LPRECT
) HeapAlloc( hProcessHeap
, 0, sizeof(RECT
) );
78 GetCharacterRect(uFontRow
, uFontColumn
, pCharacterRect
);
81 // Select the new character
82 Info
->uSelectedCharacter
= uNewCharacter
;
83 InvalidateRect(Info
->hFontBoxesWnd
, pCharacterRect
, FALSE
);
86 HeapFree(hProcessHeap
, 0, pCharacterRect
);
90 DrawProc(IN PFONT_WND_INFO Info
, IN PAINTSTRUCT
* ps
)
92 COLORREF clBackground
;
106 UCHAR uCharacterColumn
;
113 hBoxDC
= CreateCompatibleDC(NULL
);
114 hBitmapOld
= SelectObject(hBoxDC
, Info
->MainWndInfo
->hBoxBmp
);
116 hFont
= CreateFontW(13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L
"Tahoma");
117 hOldFont
= SelectObject(ps
->hdc
, hFont
);
119 SetBkMode( ps
->hdc
, TRANSPARENT
);
121 // What ranges do we have to draw?
122 uStartRow
= ps
->rcPaint
.top
/ (CHARACTER_BOX_HEIGHT
+ CHARACTER_BOX_PADDING
);
123 uEndRow
= ps
->rcPaint
.bottom
/ (CHARACTER_BOX_HEIGHT
+ CHARACTER_BOX_PADDING
);
124 uStartColumn
= ps
->rcPaint
.left
/ (CHARACTER_BOX_WIDTH
+ CHARACTER_BOX_PADDING
);
125 uEndColumn
= ps
->rcPaint
.right
/ (CHARACTER_BOX_WIDTH
+ CHARACTER_BOX_PADDING
);
127 for(uFontRow
= uStartRow
; uFontRow
<= uEndRow
; uFontRow
++)
129 for(uFontColumn
= uStartColumn
; uFontColumn
<= uEndColumn
; uFontColumn
++)
131 GetCharacterRect(uFontRow
, uFontColumn
, &CharacterRect
);
132 uCharacter
= uFontRow
* 16 + uFontColumn
;
134 // Draw the Character Info Box (header)
139 CHARACTER_INFO_BOX_HEIGHT
,
145 // Draw the header text
146 wsprintfW(szInfoText
, L
"%02u = %02X", uCharacter
, uCharacter
);
147 DrawTextW( ps
->hdc
, szInfoText
, -1, &CharacterRect
, DT_CENTER
);
149 // Draw the Character Bitmap Box (rectangle with the actual character)
150 if(Info
->uSelectedCharacter
== uCharacter
)
152 clBackground
= RGB(255, 255, 0);
153 hBrush
= CreateSolidBrush(clBackground
);
154 hOldBrush
= SelectObject(ps
->hdc
, hBrush
);
158 clBackground
= RGB(255, 255, 255);
159 SelectObject( ps
->hdc
, GetStockObject(WHITE_BRUSH
) );
164 CharacterRect
.top
+ CHARACTER_INFO_BOX_HEIGHT
,
166 CharacterRect
.bottom
);
168 // Draw the actual character into the box
169 for(uCharacterRow
= 0; uCharacterRow
< 8; uCharacterRow
++)
171 for(uCharacterColumn
= 0; uCharacterColumn
< 8; uCharacterColumn
++)
173 uBit
= Info
->Font
->Bits
[uCharacter
* 8 + uCharacterRow
] << uCharacterColumn
& 0x80;
174 DrawCharacterPixel(ps
, uCharacter
, uCharacterRow
, uCharacterColumn
, uBit
, clBackground
);
180 SelectObject(hBoxDC
, hBitmapOld
);
181 SelectObject(ps
->hdc
, hOldFont
);
183 SelectObject(ps
->hdc
, hOldBrush
);
184 DeleteObject(hBrush
);
189 EditCurrentGlyph(PFONT_WND_INFO FontWndInfo
)
191 PEDIT_GLYPH_INFO EditGlyphInfo
;
193 // Has the window for this character already been opened?
194 EditGlyphInfo
= FontWndInfo
->FirstEditGlyphWnd
;
198 if(EditGlyphInfo
->uCharacter
== FontWndInfo
->uSelectedCharacter
)
200 // Yes, it has. Bring it to the front.
201 SetFocus(EditGlyphInfo
->hSelf
);
205 EditGlyphInfo
= EditGlyphInfo
->NextEditGlyphWnd
;
208 // No. Then create a new one
209 EditGlyphInfo
= (PEDIT_GLYPH_INFO
) HeapAlloc( hProcessHeap
, 0, sizeof(EDIT_GLYPH_INFO
) );
210 EditGlyphInfo
->FontWndInfo
= FontWndInfo
;
211 EditGlyphInfo
->uCharacter
= FontWndInfo
->uSelectedCharacter
;
212 RtlCopyMemory( EditGlyphInfo
->CharacterBits
, FontWndInfo
->Font
->Bits
+ FontWndInfo
->uSelectedCharacter
* 8, sizeof(EditGlyphInfo
->CharacterBits
) );
214 // Add the new window to the linked list
215 EditGlyphInfo
->PrevEditGlyphWnd
= FontWndInfo
->LastEditGlyphWnd
;
216 EditGlyphInfo
->NextEditGlyphWnd
= NULL
;
218 if(FontWndInfo
->LastEditGlyphWnd
)
219 FontWndInfo
->LastEditGlyphWnd
->NextEditGlyphWnd
= EditGlyphInfo
;
221 FontWndInfo
->FirstEditGlyphWnd
= EditGlyphInfo
;
223 FontWndInfo
->LastEditGlyphWnd
= EditGlyphInfo
;
225 // Open the window as a modeless dialog, so people can edit several characters at the same time.
226 EditGlyphInfo
->hSelf
= CreateDialogParamW(hInstance
, MAKEINTRESOURCEW(IDD_EDITGLYPH
), FontWndInfo
->hSelf
, EditGlyphDlgProc
, (LPARAM
)EditGlyphInfo
);
227 ShowWindow(EditGlyphInfo
->hSelf
, SW_SHOW
);
231 CreateFontBoxesWindow(IN PFONT_WND_INFO FontWndInfo
)
233 FontWndInfo
->hFontBoxesWnd
= CreateWindowExW(0,
236 WS_CHILD
| WS_VISIBLE
,
247 static LRESULT CALLBACK
248 FontBoxesWndProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
252 Info
= (PFONT_WND_INFO
) GetWindowLongW(hwnd
, GWLP_USERDATA
);
254 if(Info
|| uMsg
== WM_CREATE
)
259 Info
= (PFONT_WND_INFO
)( ( (LPCREATESTRUCT
)lParam
)->lpCreateParams
);
260 SetWindowLongW(hwnd
, GWLP_USERDATA
, (LONG
)Info
);
262 // Set a fixed window size
263 SetWindowPos(hwnd
, NULL
, 0, 0, FONT_BOXES_WND_WIDTH
, FONT_BOXES_WND_HEIGHT
, SWP_NOZORDER
| SWP_NOMOVE
);
268 SetWindowLongW(hwnd
, GWLP_USERDATA
, 0);
275 if(Info
->uSelectedCharacter
< 239)
276 SetSelectedCharacter(Info
, Info
->uSelectedCharacter
+ 16, NULL
);
280 if(Info
->uSelectedCharacter
)
281 SetSelectedCharacter(Info
, Info
->uSelectedCharacter
- 1, NULL
);
285 EditCurrentGlyph(Info
);
289 if(Info
->uSelectedCharacter
< 255)
290 SetSelectedCharacter(Info
, Info
->uSelectedCharacter
+ 1, NULL
);
294 if(Info
->uSelectedCharacter
> 15)
295 SetSelectedCharacter(Info
, Info
->uSelectedCharacter
- 16, NULL
);
301 case WM_LBUTTONDBLCLK
:
303 EditCurrentGlyph(Info
);
312 iRet
= FontBoxesHitTest( GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
), &CharacterRect
);
315 SetSelectedCharacter( Info
, (UINT
)iRet
, &CharacterRect
);
324 BeginPaint(hwnd
, &ps
);
333 return DefWindowProcW(hwnd
, uMsg
, wParam
, lParam
);
337 InitFontBoxesWndClass(VOID
)
341 wc
.lpfnWndProc
= FontBoxesWndProc
;
342 wc
.hInstance
= hInstance
;
343 wc
.hCursor
= LoadCursor( NULL
, IDC_ARROW
);
344 wc
.hbrBackground
= (HBRUSH
)( COLOR_BTNFACE
+ 1 );
345 wc
.lpszClassName
= szFontBoxesWndClass
;
346 wc
.style
= CS_DBLCLKS
;
348 return RegisterClassW(&wc
) != 0;
352 UnInitFontBoxesWndClass(VOID
)
354 UnregisterClassW(szFontBoxesWndClass
, hInstance
);