- Rearrange reactos.dff according to rosapps rearrange.
[reactos.git] / rosapps / devutils / vgafontedit / fontboxeswnd.c
1 /*
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>
7 */
8
9 #include "precomp.h"
10
11 static const WCHAR szFontBoxesWndClass[] = L"VGAFontEditFontBoxesWndClass";
12
13 static VOID
14 DrawCharacterPixel(IN PAINTSTRUCT *ps, IN UINT uCharacter, IN UCHAR uRow, IN UCHAR uColumn, IN UCHAR uBit, IN COLORREF clBackground)
15 {
16 INT x;
17 INT y;
18
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;
21
22 SetPixel( ps->hdc, x, y, (uBit ? 0 : clBackground) );
23 }
24
25 VOID
26 GetCharacterRect(IN UINT uFontRow, IN UINT uFontColumn, OUT LPRECT CharacterRect)
27 {
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;
32 }
33
34 __inline VOID
35 GetCharacterPosition(IN UINT uCharacter, OUT PUINT uFontRow, OUT PUINT uFontColumn)
36 {
37 *uFontRow = uCharacter / 16;
38 *uFontColumn = uCharacter % 16;
39 }
40
41 static INT
42 FontBoxesHitTest(IN UINT xPos, IN UINT yPos, OUT LPRECT CharacterRect)
43 {
44 UINT uFontColumn;
45 UINT uFontRow;
46
47 uFontColumn = xPos / (CHARACTER_BOX_WIDTH + CHARACTER_BOX_PADDING);
48 uFontRow = yPos / (CHARACTER_BOX_HEIGHT + CHARACTER_BOX_PADDING);
49 GetCharacterRect(uFontRow, uFontColumn, CharacterRect);
50
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;
54 else
55 // Return the character number
56 return (uFontRow * 16 + uFontColumn);
57 }
58
59 static VOID
60 SetSelectedCharacter(IN PFONT_WND_INFO Info, IN UINT uNewCharacter, OPTIONAL IN LPRECT NewCharacterRect)
61 {
62 LPRECT pCharacterRect;
63 RECT OldCharacterRect;
64 UINT uFontColumn;
65 UINT uFontRow;
66
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);
71
72 // You may pass the RECT of the new character, otherwise we'll allocate memory for one and get it ourselves
73 if(NewCharacterRect)
74 pCharacterRect = NewCharacterRect;
75 else
76 {
77 GetCharacterPosition(uNewCharacter, &uFontRow, &uFontColumn);
78 pCharacterRect = (LPRECT) HeapAlloc( hProcessHeap, 0, sizeof(RECT) );
79 GetCharacterRect(uFontRow, uFontColumn, pCharacterRect);
80 }
81
82 // Select the new character
83 Info->uSelectedCharacter = uNewCharacter;
84 InvalidateRect(Info->hFontBoxesWnd, pCharacterRect, FALSE);
85
86 if(!NewCharacterRect)
87 HeapFree(hProcessHeap, 0, pCharacterRect);
88 }
89
90 static VOID
91 DrawProc(IN PFONT_WND_INFO Info, IN PAINTSTRUCT* ps)
92 {
93 COLORREF clBackground;
94 HBRUSH hBrush = 0;
95 HBRUSH hOldBrush = 0;
96 HDC hBoxDC;
97 HFONT hFont;
98 HFONT hOldFont;
99 RECT CharacterRect;
100 UINT uFontColumn;
101 UINT uStartColumn;
102 UINT uEndColumn;
103 UINT uFontRow;
104 UINT uStartRow;
105 UINT uEndRow;
106 UINT uCharacter;
107 UCHAR uCharacterColumn;
108 UCHAR uCharacterRow;
109 UCHAR uBit;
110 WCHAR szInfoText[9];
111
112 // Preparations
113 hBoxDC = CreateCompatibleDC(NULL);
114 SelectObject(hBoxDC, Info->MainWndInfo->hBoxBmp);
115
116 hFont = CreateFontW(13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L"Tahoma");
117 hOldFont = SelectObject(ps->hdc, hFont);
118
119 SetBkMode( ps->hdc, TRANSPARENT );
120
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);
126
127 for(uFontRow = uStartRow; uFontRow <= uEndRow; uFontRow++)
128 {
129 for(uFontColumn = uStartColumn; uFontColumn <= uEndColumn; uFontColumn++)
130 {
131 GetCharacterRect(uFontRow, uFontColumn, &CharacterRect);
132 uCharacter = uFontRow * 16 + uFontColumn;
133
134 // Draw the Character Info Box (header)
135 BitBlt(ps->hdc,
136 CharacterRect.left,
137 CharacterRect.top,
138 CHARACTER_BOX_WIDTH,
139 CHARACTER_INFO_BOX_HEIGHT,
140 hBoxDC,
141 0,
142 0,
143 SRCCOPY);
144
145 // Draw the header text
146 wsprintfW(szInfoText, L"%02u = %02X", uCharacter, uCharacter);
147 DrawTextW( ps->hdc, szInfoText, -1, &CharacterRect, DT_CENTER );
148
149 // Draw the Character Bitmap Box (rectangle with the actual character)
150 if(Info->uSelectedCharacter == uCharacter)
151 {
152 clBackground = RGB(255, 255, 0);
153 hBrush = CreateSolidBrush(clBackground);
154 hOldBrush = SelectObject(ps->hdc, hBrush);
155 }
156 else
157 {
158 clBackground = RGB(255, 255, 255);
159 SelectObject( ps->hdc, GetStockObject(WHITE_BRUSH) );
160 }
161
162 Rectangle(ps->hdc,
163 CharacterRect.left,
164 CharacterRect.top + CHARACTER_INFO_BOX_HEIGHT,
165 CharacterRect.right,
166 CharacterRect.bottom);
167
168 // Draw the actual character into the box
169 for(uCharacterRow = 0; uCharacterRow < 8; uCharacterRow++)
170 {
171 for(uCharacterColumn = 0; uCharacterColumn < 8; uCharacterColumn++)
172 {
173 uBit = Info->Font->Bits[uCharacter * 8 + uCharacterRow] << uCharacterColumn & 0x80;
174 DrawCharacterPixel(ps, uCharacter, uCharacterRow, uCharacterColumn, uBit, clBackground);
175 }
176 }
177 }
178 }
179
180 SelectObject(ps->hdc, hOldFont);
181 DeleteObject(hFont);
182 SelectObject(ps->hdc, hOldBrush);
183 DeleteObject(hBrush);
184 DeleteDC(hBoxDC);
185 }
186
187 VOID
188 EditCurrentGlyph(PFONT_WND_INFO FontWndInfo)
189 {
190 PEDIT_GLYPH_INFO EditGlyphInfo;
191
192 // Has the window for this character already been opened?
193 EditGlyphInfo = FontWndInfo->FirstEditGlyphWnd;
194
195 while(EditGlyphInfo)
196 {
197 if(EditGlyphInfo->uCharacter == FontWndInfo->uSelectedCharacter)
198 {
199 // Yes, it has. Bring it to the front.
200 SetFocus(EditGlyphInfo->hSelf);
201 return;
202 }
203
204 EditGlyphInfo = EditGlyphInfo->NextEditGlyphWnd;
205 }
206
207 // No. Then create a new one
208 EditGlyphInfo = (PEDIT_GLYPH_INFO) HeapAlloc( hProcessHeap, 0, sizeof(EDIT_GLYPH_INFO) );
209 EditGlyphInfo->FontWndInfo = FontWndInfo;
210 EditGlyphInfo->uCharacter = FontWndInfo->uSelectedCharacter;
211 RtlCopyMemory( EditGlyphInfo->CharacterBits, FontWndInfo->Font->Bits + FontWndInfo->uSelectedCharacter * 8, sizeof(EditGlyphInfo->CharacterBits) );
212
213 // Add the new window to the linked list
214 EditGlyphInfo->PrevEditGlyphWnd = FontWndInfo->LastEditGlyphWnd;
215 EditGlyphInfo->NextEditGlyphWnd = NULL;
216
217 if(FontWndInfo->LastEditGlyphWnd)
218 FontWndInfo->LastEditGlyphWnd->NextEditGlyphWnd = EditGlyphInfo;
219 else
220 FontWndInfo->FirstEditGlyphWnd = EditGlyphInfo;
221
222 FontWndInfo->LastEditGlyphWnd = EditGlyphInfo;
223
224 // Open the window as a modeless dialog, so people can edit several characters at the same time.
225 EditGlyphInfo->hSelf = CreateDialogParamW(hInstance, MAKEINTRESOURCEW(IDD_EDITGLYPH), FontWndInfo->hSelf, EditGlyphDlgProc, (LPARAM)EditGlyphInfo);
226 ShowWindow(EditGlyphInfo->hSelf, SW_SHOW);
227 }
228
229 VOID
230 CreateFontBoxesWindow(IN PFONT_WND_INFO FontWndInfo)
231 {
232 FontWndInfo->hFontBoxesWnd = CreateWindowExW(0,
233 szFontBoxesWndClass,
234 0,
235 WS_CHILD | WS_VISIBLE,
236 0,
237 0,
238 0,
239 0,
240 FontWndInfo->hSelf,
241 NULL,
242 hInstance,
243 FontWndInfo);
244 }
245
246 static LRESULT CALLBACK
247 FontBoxesWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
248 {
249 PFONT_WND_INFO Info;
250
251 Info = (PFONT_WND_INFO) GetWindowLongW(hwnd, GWLP_USERDATA);
252
253 if(Info || uMsg == WM_CREATE)
254 {
255 switch(uMsg)
256 {
257 case WM_CREATE:
258 Info = (PFONT_WND_INFO)( ( (LPCREATESTRUCT)lParam )->lpCreateParams );
259 SetWindowLongW(hwnd, GWLP_USERDATA, (LONG)Info);
260
261 // Set a fixed window size
262 SetWindowPos(hwnd, NULL, 0, 0, FONT_BOXES_WND_WIDTH, FONT_BOXES_WND_HEIGHT, SWP_NOZORDER | SWP_NOMOVE);
263
264 return 0;
265
266 case WM_DESTROY:
267 SetWindowLongW(hwnd, GWLP_USERDATA, 0);
268 return 0;
269
270 case WM_KEYDOWN:
271 switch(wParam)
272 {
273 case VK_DOWN:
274 if(Info->uSelectedCharacter < 239)
275 SetSelectedCharacter(Info, Info->uSelectedCharacter + 16, NULL);
276 return 0;
277
278 case VK_LEFT:
279 if(Info->uSelectedCharacter)
280 SetSelectedCharacter(Info, Info->uSelectedCharacter - 1, NULL);
281 return 0;
282
283 case VK_RETURN:
284 EditCurrentGlyph(Info);
285 return 0;
286
287 case VK_RIGHT:
288 if(Info->uSelectedCharacter < 255)
289 SetSelectedCharacter(Info, Info->uSelectedCharacter + 1, NULL);
290 return 0;
291
292 case VK_UP:
293 if(Info->uSelectedCharacter > 15)
294 SetSelectedCharacter(Info, Info->uSelectedCharacter - 16, NULL);
295 return 0;
296 }
297
298 break;
299
300 case WM_LBUTTONDBLCLK:
301 {
302 EditCurrentGlyph(Info);
303 return 0;
304 }
305
306 case WM_LBUTTONDOWN:
307 {
308 RECT CharacterRect;
309 INT iRet;
310
311 iRet = FontBoxesHitTest( GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), &CharacterRect );
312
313 if(iRet >= 0)
314 SetSelectedCharacter( Info, (UINT)iRet, &CharacterRect );
315
316 return 0;
317 }
318
319 case WM_PAINT:
320 {
321 PAINTSTRUCT ps;
322
323 BeginPaint(hwnd, &ps);
324 DrawProc(Info, &ps);
325 EndPaint(hwnd, &ps);
326
327 return 0;
328 }
329 }
330 }
331
332 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
333 }
334
335 BOOL
336 InitFontBoxesWndClass(VOID)
337 {
338 WNDCLASSW wc = {0,};
339
340 wc.lpfnWndProc = FontBoxesWndProc;
341 wc.hInstance = hInstance;
342 wc.hCursor = LoadCursor( NULL, IDC_ARROW );
343 wc.hbrBackground = (HBRUSH)( COLOR_BTNFACE + 1 );
344 wc.lpszClassName = szFontBoxesWndClass;
345 wc.style = CS_DBLCLKS;
346
347 return RegisterClassW(&wc) != 0;
348 }
349
350 VOID
351 UnInitFontBoxesWndClass(VOID)
352 {
353 UnregisterClassW(szFontBoxesWndClass, hInstance);
354 }