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