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>
11 static const WCHAR szFontWndClass
[] = L
"VGAFontEditFontWndClass";
14 InitFont(IN PFONT_WND_INFO Info
)
16 Info
->Font
= (PBITMAP_FONT
) HeapAlloc( hProcessHeap
, 0, sizeof(BITMAP_FONT
) );
18 if(Info
->OpenInfo
->bCreateNew
)
20 ZeroMemory( Info
->Font
, sizeof(BITMAP_FONT
) );
30 hFile
= CreateFileW(Info
->OpenInfo
->pszFileName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
32 if(hFile
== INVALID_HANDLE_VALUE
)
34 LocalizedError( IDS_OPENERROR
, GetLastError() );
38 // Let's first check the file size to determine the file type
39 dwTemp
= GetFileSize(hFile
, NULL
);
44 // It should be a binary font file
45 Info
->OpenInfo
->bBinaryFileOpened
= TRUE
;
47 if( ReadFile(hFile
, Info
->Font
, sizeof(BITMAP_FONT
), &dwTemp
, NULL
) )
50 LocalizedError( IDS_READERROR
, GetLastError() );
58 // Probably it's a PSFv1 file, check the header to make sure
59 if( !ReadFile(hFile
, &Header
, sizeof(PSF1_HEADER
) , &dwTemp
, NULL
) )
61 LocalizedError( IDS_READERROR
, GetLastError() );
66 if(Header
.uMagic
[0] == PSF1_MAGIC0
&& Header
.uMagic
[1] == PSF1_MAGIC1
)
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)
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
) )
76 LocalizedError( IDS_READERROR
, GetLastError() );
79 LocalizedError(IDS_UNSUPPORTEDPSF
);
84 // Fall through if the magic numbers aren't there
89 LocalizedError(IDS_UNSUPPORTEDFORMAT
);
97 static LRESULT CALLBACK
98 FontWndProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
102 Info
= (PFONT_WND_INFO
) GetWindowLongW(hwnd
, GWLP_USERDATA
);
104 if(Info
|| uMsg
== WM_CREATE
)
108 case WM_CHILDACTIVATE
:
109 Info
->MainWndInfo
->CurrentFontWnd
= Info
;
110 SetToolbarFileButtonState(Info
->MainWndInfo
, TRUE
);
111 SetPasteButtonState(Info
->MainWndInfo
);
115 Info
= (PFONT_WND_INFO
)( ( (LPMDICREATESTRUCT
) ( (LPCREATESTRUCT
)lParam
)->lpCreateParams
)->lParam
);
118 SetWindowLongW(hwnd
, GWLP_USERDATA
, (LONG
)Info
);
120 CreateFontBoxesWindow(Info
);
124 case WM_USER_APPCLOSE
:
126 // The user has to close all open edit dialogs first
127 if(Info
->FirstEditGlyphWnd
)
131 AllocAndLoadString(&pszMessage
, IDS_CLOSEEDIT
);
132 MessageBoxW(hwnd
, pszMessage
, szAppName
, MB_OK
| MB_ICONEXCLAMATION
);
133 HeapFree(hProcessHeap
, 0, pszMessage
);
138 // Prompt if the current file has been modified
139 if(Info
->OpenInfo
->bModified
)
143 WCHAR szFile
[MAX_PATH
];
145 GetWindowTextW(hwnd
, szFile
, MAX_PATH
);
146 LoadAndFormatString(IDS_SAVEPROMPT
, &pszPrompt
, szFile
);
148 nMsgBoxResult
= MessageBoxW(hwnd
, pszPrompt
, szAppName
, MB_YESNOCANCEL
| MB_ICONQUESTION
);
149 HeapFree(hProcessHeap
, 0, pszPrompt
);
151 switch(nMsgBoxResult
)
154 DoFileSave(Info
->MainWndInfo
, FALSE
);
158 // 0 = Stop the process of closing the windows (same value for both WM_CLOSE and WM_USER_APPCLOSE)
161 // IDNO is handled automatically
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
);
171 if(uMsg
== WM_USER_APPCLOSE
)
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);
181 // Remove the window from the linked list
182 if(Info
->PrevFontWnd
)
183 Info
->PrevFontWnd
->NextFontWnd
= Info
->NextFontWnd
;
185 Info
->MainWndInfo
->FirstFontWnd
= Info
->NextFontWnd
;
187 if(Info
->NextFontWnd
)
188 Info
->NextFontWnd
->PrevFontWnd
= Info
->PrevFontWnd
;
190 Info
->MainWndInfo
->LastFontWnd
= Info
->PrevFontWnd
;
194 HeapFree(hProcessHeap
, 0, Info
->Font
);
196 if(Info
->OpenInfo
->pszFileName
)
197 HeapFree(hProcessHeap
, 0, Info
->OpenInfo
->pszFileName
);
199 HeapFree(hProcessHeap
, 0, Info
->OpenInfo
);
200 HeapFree(hProcessHeap
, 0, Info
);
202 SetWindowLongW(hwnd
, GWLP_USERDATA
, 0);
206 // Set the keyboard focus to the FontBoxes window every time the Font window gets the focus
207 SetFocus(Info
->hFontBoxesWnd
);
212 INT nHeight
= HIWORD(lParam
);
213 INT nWidth
= LOWORD(lParam
);
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
);
221 ScreenToClient(hwnd
, &pt
);
223 if(nHeight
< FONT_BOXES_WND_HEIGHT
)
227 // Set the vertical scroll bar
228 si
.cbSize
= sizeof(si
);
229 si
.fMask
= SIF_RANGE
| SIF_PAGE
;
231 si
.nMax
= FONT_BOXES_WND_HEIGHT
;
233 SetScrollInfo(hwnd
, SB_VERT
, &si
, TRUE
);
237 ShowScrollBar(hwnd
, SB_VERT
, FALSE
);
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
,
247 SWP_NOSIZE
| SWP_NOZORDER
);
250 if(nWidth
< FONT_BOXES_WND_WIDTH
)
254 // Set the horizontal scroll bar
255 si
.cbSize
= sizeof(si
);
256 si
.fMask
= SIF_RANGE
| SIF_PAGE
;
258 si
.nMax
= FONT_BOXES_WND_WIDTH
;
260 SetScrollInfo(hwnd
, SB_HORZ
, &si
, TRUE
);
264 ShowScrollBar(hwnd
, SB_HORZ
, FALSE
);
266 SetWindowPos(Info
->hFontBoxesWnd
,
268 nWidth
/ 2 - FONT_BOXES_WND_WIDTH
/ 2,
272 SWP_NOSIZE
| SWP_NOZORDER
);
275 // We have to call DefMDIChildProcW here as well, otherwise we won't get the Minimize/Maximize/Close buttons for a maximized MDI child.
286 if(uMsg
== WM_HSCROLL
)
291 si
.cbSize
= sizeof(si
);
293 GetScrollInfo(hwnd
, nBar
, &si
);
297 switch( LOWORD(wParam
) )
299 // Constant is the same as SB_LEFT for WM_HSCROLL
304 // Constant is the same as SB_RIGHT for WM_HSCROLL
309 // Constant is the same as SB_LINELEFT for WM_HSCROLL
314 // Constant is the same as SB_LINERIGHT for WM_HSCROLL
319 // Constant is the same as SB_PAGELEFT for WM_HSCROLL
324 // Constant is the same as SB_PAGERIGHT for WM_HSCROLL
330 si
.nPos
= si
.nTrackPos
;
335 SetScrollInfo(hwnd
, nBar
, &si
, TRUE
);
336 GetScrollInfo(hwnd
, nBar
, &si
);
338 if(si
.nPos
!= nOrgPos
)
340 // This ugly workaround is necessary for not setting the x coordinate
344 GetWindowRect(Info
->hFontBoxesWnd
, &WndRect
);
347 ScreenToClient(hwnd
, &pt
);
349 if(uMsg
== WM_HSCROLL
)
350 SetWindowPos(Info
->hFontBoxesWnd
, NULL
, -si
.nPos
, pt
.y
, 0, 0, SWP_NOZORDER
| SWP_NOSIZE
);
352 SetWindowPos(Info
->hFontBoxesWnd
, NULL
, pt
.x
, -si
.nPos
, 0, 0, SWP_NOZORDER
| SWP_NOSIZE
);
360 return DefMDIChildProcW(hwnd
, uMsg
, wParam
, lParam
);
364 CreateFontWindow(IN PMAIN_WND_INFO MainWndInfo
, IN PFONT_OPEN_INFO OpenInfo
)
369 Info
= (PFONT_WND_INFO
) HeapAlloc( hProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(FONT_WND_INFO
) );
373 Info
->MainWndInfo
= MainWndInfo
;
374 Info
->OpenInfo
= OpenInfo
;
378 PWSTR pszWindowTitle
;
380 if(OpenInfo
->pszFileName
)
381 pszWindowTitle
= wcsrchr(OpenInfo
->pszFileName
, '\\') + 1;
383 LoadAndFormatString(IDS_DOCNAME
, &pszWindowTitle
, ++MainWndInfo
->uDocumentCounter
);
385 hFontWnd
= CreateMDIWindowW( szFontWndClass
,
392 MainWndInfo
->hMdiClient
,
396 if(!OpenInfo
->pszFileName
)
397 HeapFree(hProcessHeap
, 0, pszWindowTitle
);
401 // Add the new window to the linked list
402 Info
->PrevFontWnd
= Info
->MainWndInfo
->LastFontWnd
;
404 if(Info
->MainWndInfo
->LastFontWnd
)
405 Info
->MainWndInfo
->LastFontWnd
->NextFontWnd
= Info
;
407 Info
->MainWndInfo
->FirstFontWnd
= Info
;
409 Info
->MainWndInfo
->LastFontWnd
= Info
;
415 HeapFree(hProcessHeap
, 0, Info
);
422 InitFontWndClass(VOID
)
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
;
433 return RegisterClassW(&wc
) != 0;
437 UnInitFontWndClass(VOID
)
439 UnregisterClassW(szFontWndClass
, hInstance
);