[HEADERS]
[reactos.git] / rosapps / applications / devutils / vgafontedit / fontwnd.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/fontwnd.c
5 * PURPOSE: Implements the MDI child window for a font
6 * COPYRIGHT: Copyright 2008 Colin Finck <mail@colinfinck.de>
7 */
8
9 #include "precomp.h"
10
11 static const WCHAR szFontWndClass[] = L"VGAFontEditFontWndClass";
12
13 static BOOL
14 InitFont(IN PFONT_WND_INFO Info)
15 {
16 Info->Font = (PBITMAP_FONT) HeapAlloc( hProcessHeap, 0, sizeof(BITMAP_FONT) );
17
18 if(Info->OpenInfo->bCreateNew)
19 {
20 ZeroMemory( Info->Font, sizeof(BITMAP_FONT) );
21 return TRUE;
22 }
23 else
24 {
25 // Load a font
26 BOOL bRet = FALSE;
27 DWORD dwTemp;
28 HANDLE hFile;
29
30 hFile = CreateFileW(Info->OpenInfo->pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
31
32 if(hFile == INVALID_HANDLE_VALUE)
33 {
34 LocalizedError( IDS_OPENERROR, GetLastError() );
35 return FALSE;
36 }
37
38 // Let's first check the file size to determine the file type
39 dwTemp = GetFileSize(hFile, NULL);
40
41 switch(dwTemp)
42 {
43 case 2048:
44 // It should be a binary font file
45 Info->OpenInfo->bBinaryFileOpened = TRUE;
46
47 if( ReadFile(hFile, Info->Font, sizeof(BITMAP_FONT), &dwTemp, NULL) )
48 bRet = TRUE;
49 else
50 LocalizedError( IDS_READERROR, GetLastError() );
51
52 break;
53
54 case 2052:
55 {
56 PSF1_HEADER Header;
57
58 // Probably it's a PSFv1 file, check the header to make sure
59 if( !ReadFile(hFile, &Header, sizeof(PSF1_HEADER) , &dwTemp, NULL) )
60 {
61 LocalizedError( IDS_READERROR, GetLastError() );
62 break;
63 }
64 else
65 {
66 if(Header.uMagic[0] == PSF1_MAGIC0 && Header.uMagic[1] == PSF1_MAGIC1)
67 {
68 // Yes, it is a PSFv1 file.
69 // Check the mode and character size. We only support 8x8 fonts with no special mode.
70 if(Header.uCharSize == 8 && Header.uMode == 0)
71 {
72 // Perfect! The file pointer is already set correctly, so we can just read the font bitmap now.
73 if( ReadFile(hFile, Info->Font, sizeof(BITMAP_FONT), &dwTemp, NULL) )
74 bRet = TRUE;
75 else
76 LocalizedError( IDS_READERROR, GetLastError() );
77 }
78 else
79 LocalizedError(IDS_UNSUPPORTEDPSF);
80
81 break;
82 }
83
84 // Fall through if the magic numbers aren't there
85 }
86 }
87
88 default:
89 LocalizedError(IDS_UNSUPPORTEDFORMAT);
90 }
91
92 CloseHandle(hFile);
93 return bRet;
94 }
95 }
96
97 static LRESULT CALLBACK
98 FontWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
99 {
100 PFONT_WND_INFO Info;
101
102 Info = (PFONT_WND_INFO) GetWindowLongW(hwnd, GWLP_USERDATA);
103
104 if(Info || uMsg == WM_CREATE)
105 {
106 switch(uMsg)
107 {
108 case WM_CHILDACTIVATE:
109 Info->MainWndInfo->CurrentFontWnd = Info;
110 SetToolbarFileButtonState(Info->MainWndInfo, TRUE);
111 SetPasteButtonState(Info->MainWndInfo);
112 break;
113
114 case WM_CREATE:
115 Info = (PFONT_WND_INFO)( ( (LPMDICREATESTRUCT) ( (LPCREATESTRUCT)lParam )->lpCreateParams )->lParam );
116 Info->hSelf = hwnd;
117
118 SetWindowLongW(hwnd, GWLP_USERDATA, (LONG)Info);
119
120 CreateFontBoxesWindow(Info);
121
122 return 0;
123
124 case WM_USER_APPCLOSE:
125 case WM_CLOSE:
126 // The user has to close all open edit dialogs first
127 if(Info->FirstEditGlyphWnd)
128 {
129 PWSTR pszMessage;
130
131 AllocAndLoadString(&pszMessage, IDS_CLOSEEDIT);
132 MessageBoxW(hwnd, pszMessage, szAppName, MB_OK | MB_ICONEXCLAMATION);
133 HeapFree(hProcessHeap, 0, pszMessage);
134
135 return 0;
136 }
137
138 // Prompt if the current file has been modified
139 if(Info->OpenInfo->bModified)
140 {
141 INT nMsgBoxResult;
142 PWSTR pszPrompt;
143 WCHAR szFile[MAX_PATH];
144
145 GetWindowTextW(hwnd, szFile, MAX_PATH);
146 LoadAndFormatString(IDS_SAVEPROMPT, &pszPrompt, szFile);
147
148 nMsgBoxResult = MessageBoxW(hwnd, pszPrompt, szAppName, MB_YESNOCANCEL | MB_ICONQUESTION);
149 LocalFree(pszPrompt);
150
151 switch(nMsgBoxResult)
152 {
153 case IDYES:
154 DoFileSave(Info->MainWndInfo, FALSE);
155 break;
156
157 case IDCANCEL:
158 // 0 = Stop the process of closing the windows (same value for both WM_CLOSE and WM_USER_APPCLOSE)
159 return 0;
160
161 // IDNO is handled automatically
162 }
163 }
164
165 // If there is another child, it will undo the following actions through its WM_CHILDACTIVATE handler.
166 // Otherwise CurrentFontWnd will stay NULL, so the main window knows that no more childs are opened.
167 Info->MainWndInfo->CurrentFontWnd = NULL;
168 SetToolbarFileButtonState(Info->MainWndInfo, FALSE);
169 SetPasteButtonState(Info->MainWndInfo);
170
171 if(uMsg == WM_USER_APPCLOSE)
172 {
173 // First do the tasks we would do for a normal WM_CLOSE message, then return the value for WM_USER_APPCLOSE
174 // Anything other than 0 indicates that the application shall continue closing the windows
175 DefMDIChildProcW(hwnd, WM_CLOSE, 0, 0);
176 return 1;
177 }
178 break;
179
180 case WM_DESTROY:
181 // Remove the window from the linked list
182 if(Info->PrevFontWnd)
183 Info->PrevFontWnd->NextFontWnd = Info->NextFontWnd;
184 else
185 Info->MainWndInfo->FirstFontWnd = Info->NextFontWnd;
186
187 if(Info->NextFontWnd)
188 Info->NextFontWnd->PrevFontWnd = Info->PrevFontWnd;
189 else
190 Info->MainWndInfo->LastFontWnd = Info->PrevFontWnd;
191
192 // Free memory
193 if(Info->Font)
194 HeapFree(hProcessHeap, 0, Info->Font);
195
196 if(Info->OpenInfo->pszFileName)
197 HeapFree(hProcessHeap, 0, Info->OpenInfo->pszFileName);
198
199 HeapFree(hProcessHeap, 0, Info->OpenInfo);
200 HeapFree(hProcessHeap, 0, Info);
201
202 SetWindowLongW(hwnd, GWLP_USERDATA, 0);
203 return 0;
204
205 case WM_SETFOCUS:
206 // Set the keyboard focus to the FontBoxes window every time the Font window gets the focus
207 SetFocus(Info->hFontBoxesWnd);
208 break;
209
210 case WM_SIZE:
211 {
212 INT nHeight = HIWORD(lParam);
213 INT nWidth = LOWORD(lParam);
214 POINT pt;
215 RECT WndRect;
216
217 // This ugly workaround is necessary for not setting either the Height or the Width of the window with SetWindowPos
218 GetWindowRect(Info->hFontBoxesWnd, &WndRect);
219 pt.x = WndRect.left;
220 pt.y = WndRect.top;
221 ScreenToClient(hwnd, &pt);
222
223 if(nHeight < FONT_BOXES_WND_HEIGHT)
224 {
225 SCROLLINFO si;
226
227 // Set the vertical scroll bar
228 si.cbSize = sizeof(si);
229 si.fMask = SIF_RANGE | SIF_PAGE;
230 si.nMin = 0;
231 si.nMax = FONT_BOXES_WND_HEIGHT;
232 si.nPage = nHeight;
233 SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
234 }
235 else
236 {
237 ShowScrollBar(hwnd, SB_VERT, FALSE);
238
239 // Store the new y coordinate in pt.y as well (needed for the SetWindowPos call for setting a new x coordinate)
240 pt.y = nHeight / 2 - FONT_BOXES_WND_HEIGHT / 2;
241 SetWindowPos(Info->hFontBoxesWnd,
242 NULL,
243 pt.x,
244 pt.y,
245 0,
246 0,
247 SWP_NOSIZE | SWP_NOZORDER);
248 }
249
250 if(nWidth < FONT_BOXES_WND_WIDTH)
251 {
252 SCROLLINFO si;
253
254 // Set the horizontal scroll bar
255 si.cbSize = sizeof(si);
256 si.fMask = SIF_RANGE | SIF_PAGE;
257 si.nMin = 0;
258 si.nMax = FONT_BOXES_WND_WIDTH;
259 si.nPage = nWidth;
260 SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
261 }
262 else
263 {
264 ShowScrollBar(hwnd, SB_HORZ, FALSE);
265
266 SetWindowPos(Info->hFontBoxesWnd,
267 NULL,
268 nWidth / 2 - FONT_BOXES_WND_WIDTH / 2,
269 pt.y,
270 0,
271 0,
272 SWP_NOSIZE | SWP_NOZORDER);
273 }
274
275 // We have to call DefMDIChildProcW here as well, otherwise we won't get the Minimize/Maximize/Close buttons for a maximized MDI child.
276 break;
277 }
278
279 case WM_HSCROLL:
280 case WM_VSCROLL:
281 {
282 INT nBar;
283 INT nOrgPos;
284 SCROLLINFO si;
285
286 if(uMsg == WM_HSCROLL)
287 nBar = SB_HORZ;
288 else
289 nBar = SB_VERT;
290
291 si.cbSize = sizeof(si);
292 si.fMask = SIF_ALL;
293 GetScrollInfo(hwnd, nBar, &si);
294
295 nOrgPos = si.nPos;
296
297 switch( LOWORD(wParam) )
298 {
299 // Constant is the same as SB_LEFT for WM_HSCROLL
300 case SB_TOP:
301 si.nPos = si.nMin;
302 break;
303
304 // Constant is the same as SB_RIGHT for WM_HSCROLL
305 case SB_BOTTOM:
306 si.nPos = si.nMax;
307 break;
308
309 // Constant is the same as SB_LINELEFT for WM_HSCROLL
310 case SB_LINEUP:
311 si.nPos -= 20;
312 break;
313
314 // Constant is the same as SB_LINERIGHT for WM_HSCROLL
315 case SB_LINEDOWN:
316 si.nPos += 20;
317 break;
318
319 // Constant is the same as SB_PAGELEFT for WM_HSCROLL
320 case SB_PAGEUP:
321 si.nPos -= si.nPage;
322 break;
323
324 // Constant is the same as SB_PAGERIGHT for WM_HSCROLL
325 case SB_PAGEDOWN:
326 si.nPos += si.nPage;
327 break;
328
329 case SB_THUMBTRACK:
330 si.nPos = si.nTrackPos;
331 break;
332 }
333
334 si.fMask = SIF_POS;
335 SetScrollInfo(hwnd, nBar, &si, TRUE);
336 GetScrollInfo(hwnd, nBar, &si);
337
338 if(si.nPos != nOrgPos)
339 {
340 // This ugly workaround is necessary for not setting the x coordinate
341 POINT pt;
342 RECT WndRect;
343
344 GetWindowRect(Info->hFontBoxesWnd, &WndRect);
345 pt.x = WndRect.left;
346 pt.y = WndRect.top;
347 ScreenToClient(hwnd, &pt);
348
349 if(uMsg == WM_HSCROLL)
350 SetWindowPos(Info->hFontBoxesWnd, NULL, -si.nPos, pt.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
351 else
352 SetWindowPos(Info->hFontBoxesWnd, NULL, pt.x, -si.nPos, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
353 }
354
355 return 0;
356 }
357 }
358 }
359
360 return DefMDIChildProcW(hwnd, uMsg, wParam, lParam);
361 }
362
363 BOOL
364 CreateFontWindow(IN PMAIN_WND_INFO MainWndInfo, IN PFONT_OPEN_INFO OpenInfo)
365 {
366 HWND hFontWnd;
367 PFONT_WND_INFO Info;
368
369 Info = (PFONT_WND_INFO) HeapAlloc( hProcessHeap, HEAP_ZERO_MEMORY, sizeof(FONT_WND_INFO) );
370
371 if(Info)
372 {
373 Info->MainWndInfo = MainWndInfo;
374 Info->OpenInfo = OpenInfo;
375
376 if( InitFont(Info) )
377 {
378 PWSTR pszWindowTitle;
379
380 if(OpenInfo->pszFileName)
381 pszWindowTitle = wcsrchr(OpenInfo->pszFileName, '\\') + 1;
382 else
383 LoadAndFormatString(IDS_DOCNAME, &pszWindowTitle, ++MainWndInfo->uDocumentCounter);
384
385 hFontWnd = CreateMDIWindowW( szFontWndClass,
386 pszWindowTitle,
387 0,
388 CW_USEDEFAULT,
389 CW_USEDEFAULT,
390 FONT_WND_MIN_WIDTH,
391 FONT_WND_MIN_HEIGHT,
392 MainWndInfo->hMdiClient,
393 hInstance,
394 (LPARAM)Info );
395
396 if(!OpenInfo->pszFileName)
397 LocalFree(pszWindowTitle);
398
399 if(hFontWnd)
400 {
401 // Add the new window to the linked list
402 Info->PrevFontWnd = Info->MainWndInfo->LastFontWnd;
403
404 if(Info->MainWndInfo->LastFontWnd)
405 Info->MainWndInfo->LastFontWnd->NextFontWnd = Info;
406 else
407 Info->MainWndInfo->FirstFontWnd = Info;
408
409 Info->MainWndInfo->LastFontWnd = Info;
410
411 return TRUE;
412 }
413 }
414
415 HeapFree(hProcessHeap, 0, Info);
416 }
417
418 return FALSE;
419 }
420
421 BOOL
422 InitFontWndClass(VOID)
423 {
424 WNDCLASSW wc = {0,};
425
426 wc.lpfnWndProc = FontWndProc;
427 wc.hInstance = hInstance;
428 wc.hCursor = LoadCursor( NULL, IDC_ARROW );
429 wc.hIcon = LoadIconW( hInstance, MAKEINTRESOURCEW(IDI_DOC) );
430 wc.hbrBackground = (HBRUSH)( COLOR_BTNFACE + 1 );
431 wc.lpszClassName = szFontWndClass;
432
433 return RegisterClassW(&wc) != 0;
434 }
435
436 VOID
437 UnInitFontWndClass(VOID)
438 {
439 UnregisterClassW(szFontWndClass, hInstance);
440 }