2 * PROJECT: ReactOS VGA Font Editor
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Implements the main window of the application
5 * COPYRIGHT: Copyright 2008 Colin Finck (colin@reactos.org)
6 * Copyright 2018 Katayama Hirofui MZ (katayama.hirofumi.mz@gmail.com)
11 static const WCHAR szMainWndClass
[] = L
"VGAFontEditMainWndClass";
14 InitResources(IN PMAIN_WND_INFO Info
)
22 hMemDC
= CreateCompatibleDC(NULL
);
23 hMainDC
= GetDC(Info
->hMainWnd
);
25 // Create the "Box" bitmap
26 Info
->hBoxBmp
= CreateCompatibleBitmap(hMainDC
, CHARACTER_BOX_WIDTH
, CHARACTER_BOX_HEIGHT
);
27 hBitmapOld
= SelectObject(hMemDC
, Info
->hBoxBmp
);
31 rect
.right
= CHARACTER_INFO_BOX_WIDTH
;
32 rect
.bottom
= CHARACTER_INFO_BOX_HEIGHT
;
33 FillRect( hMemDC
, &rect
, (HBRUSH
)(COLOR_BTNFACE
+ 1) );
35 hPenOld
= SelectObject( hMemDC
, GetStockObject(WHITE_PEN
) );
36 Rectangle(hMemDC
, 0, 0, CHARACTER_INFO_BOX_WIDTH
- 1, 2);
37 Rectangle(hMemDC
, 0, 2, 2, CHARACTER_INFO_BOX_HEIGHT
- 1);
38 hPen
= SelectObject(hMemDC
, hPenOld
);
40 hPen
= CreatePen( PS_SOLID
, 1, RGB(128, 128, 128) );
41 hPenOld
= SelectObject(hMemDC
, hPen
);
42 Rectangle(hMemDC
, 1, CHARACTER_INFO_BOX_HEIGHT
- 2, CHARACTER_INFO_BOX_WIDTH
, CHARACTER_INFO_BOX_HEIGHT
);
43 Rectangle(hMemDC
, CHARACTER_INFO_BOX_WIDTH
- 2, 1, CHARACTER_INFO_BOX_WIDTH
, CHARACTER_INFO_BOX_HEIGHT
- 2);
45 SetPixel( hMemDC
, CHARACTER_INFO_BOX_WIDTH
- 1, 0, RGB(128, 128, 128) );
46 SetPixel( hMemDC
, 0, CHARACTER_INFO_BOX_HEIGHT
- 1, RGB(128, 128, 128) );
47 SelectObject(hMemDC
, hBitmapOld
);
49 hPen
= SelectObject(hMemDC
, hPenOld
);
52 ReleaseDC(Info
->hMainWnd
, hMainDC
);
56 UnInitResources(IN PMAIN_WND_INFO Info
)
58 DeleteObject(Info
->hBoxBmp
);
62 AddToolbarButton(IN PMAIN_WND_INFO Info
, IN INT iBitmap
, IN INT idCommand
, IN UINT uID
)
67 if( AllocAndLoadString(&pszTooltip
, uID
) )
69 tbb
.fsState
= TBSTATE_ENABLED
;
70 tbb
.iBitmap
= iBitmap
;
71 tbb
.idCommand
= idCommand
;
72 tbb
.iString
= (INT_PTR
)pszTooltip
;
74 SendMessageW( Info
->hToolbar
, TB_ADDBUTTONSW
, 1, (LPARAM
)&tbb
);
75 HeapFree(hProcessHeap
, 0, pszTooltip
);
80 SetToolbarButtonState(IN PMAIN_WND_INFO Info
, INT idCommand
, BOOL bEnabled
)
82 TBBUTTONINFOW tbbi
= {0,};
84 tbbi
.cbSize
= sizeof(tbbi
);
85 tbbi
.dwMask
= TBIF_STATE
;
86 tbbi
.fsState
= (bEnabled
? TBSTATE_ENABLED
: 0);
88 SendMessageW(Info
->hToolbar
, TB_SETBUTTONINFOW
, idCommand
, (LPARAM
)&tbbi
);
92 SetToolbarFileButtonState(IN PMAIN_WND_INFO Info
, BOOL bEnabled
)
94 SetToolbarButtonState(Info
, ID_FILE_SAVE
, bEnabled
);
95 SetToolbarButtonState(Info
, ID_EDIT_GLYPH
, bEnabled
);
96 SetToolbarButtonState(Info
, ID_EDIT_COPY
, bEnabled
);
100 AddToolbarSeparator(IN PMAIN_WND_INFO Info
)
104 tbb
.fsStyle
= BTNS_SEP
;
106 SendMessageW( Info
->hToolbar
, TB_ADDBUTTONSW
, 1, (LPARAM
)&tbb
);
110 InitMainWnd(IN PMAIN_WND_INFO Info
)
112 CLIENTCREATESTRUCT ccs
;
114 INT iStandardBitmaps
;
118 Info
->hToolbar
= CreateWindowExW(0,
121 WS_VISIBLE
| WS_CHILD
| TBSTYLE_TOOLTIPS
,
131 // Identify the used Common Controls version
132 SendMessageW(Info
->hToolbar
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
135 SendMessageW(Info
->hToolbar
, TB_SETMAXTEXTROWS
, 0, 0);
137 // Add the toolbar bitmaps
138 tbab
.hInst
= HINST_COMMCTRL
;
139 tbab
.nID
= IDB_STD_SMALL_COLOR
;
140 iStandardBitmaps
= (INT
)SendMessageW(Info
->hToolbar
, TB_ADDBITMAP
, 0, (LPARAM
)&tbab
);
142 tbab
.hInst
= hInstance
;
143 tbab
.nID
= IDB_MAIN_TOOLBAR
;
144 iCustomBitmaps
= (INT
)SendMessageW(Info
->hToolbar
, TB_ADDBITMAP
, 0, (LPARAM
)&tbab
);
146 // Add the toolbar buttons
147 AddToolbarButton(Info
, iStandardBitmaps
+ STD_FILENEW
, ID_FILE_NEW
, IDS_TOOLTIP_NEW
);
148 AddToolbarButton(Info
, iStandardBitmaps
+ STD_FILEOPEN
, ID_FILE_OPEN
, IDS_TOOLTIP_OPEN
);
149 AddToolbarButton(Info
, iStandardBitmaps
+ STD_FILESAVE
, ID_FILE_SAVE
, IDS_TOOLTIP_SAVE
);
150 AddToolbarSeparator(Info
);
151 AddToolbarButton(Info
, iCustomBitmaps
+ TOOLBAR_EDIT_GLYPH
, ID_EDIT_GLYPH
, IDS_TOOLTIP_EDIT_GLYPH
);
152 AddToolbarSeparator(Info
);
153 AddToolbarButton(Info
, iStandardBitmaps
+ STD_COPY
, ID_EDIT_COPY
, IDS_TOOLTIP_COPY
);
154 AddToolbarButton(Info
, iStandardBitmaps
+ STD_PASTE
, ID_EDIT_PASTE
, IDS_TOOLTIP_PASTE
);
156 SetToolbarFileButtonState(Info
, FALSE
);
157 SetPasteButtonState(Info
);
159 // Add the MDI client area
160 ccs
.hWindowMenu
= GetSubMenu(Info
->hMenu
, 2);
161 ccs
.idFirstChild
= ID_MDI_FIRSTCHILD
;
163 Info
->hMdiClient
= CreateWindowExW(WS_EX_CLIENTEDGE
,
166 WS_VISIBLE
| WS_CHILD
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
| WS_VSCROLL
| WS_HSCROLL
,
176 // Initialize the file handling
177 FileInitialize(Info
->hMainWnd
);
181 InitMenuPopup(IN PMAIN_WND_INFO Info
)
185 uState
= MF_BYCOMMAND
| !(Info
->CurrentFontWnd
);
187 EnableMenuItem(Info
->hMenu
, ID_FILE_CLOSE
, uState
);
188 EnableMenuItem(Info
->hMenu
, ID_FILE_SAVE
, uState
);
189 EnableMenuItem(Info
->hMenu
, ID_FILE_SAVE_AS
, uState
);
191 EnableMenuItem(Info
->hMenu
, ID_EDIT_COPY
, uState
);
192 EnableMenuItem(Info
->hMenu
, ID_EDIT_GLYPH
, uState
);
194 uState
= MF_BYCOMMAND
| !(Info
->CurrentFontWnd
&& IsClipboardFormatAvailable(uCharacterClipboardFormat
));
195 EnableMenuItem(Info
->hMenu
, ID_EDIT_PASTE
, uState
);
199 DoFileNew(IN PMAIN_WND_INFO Info
)
201 PFONT_OPEN_INFO OpenInfo
;
203 OpenInfo
= (PFONT_OPEN_INFO
) HeapAlloc( hProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(FONT_OPEN_INFO
) );
204 OpenInfo
->bCreateNew
= TRUE
;
206 CreateFontWindow(Info
, OpenInfo
);
210 DoFileOpen(IN PMAIN_WND_INFO Info
)
212 PFONT_OPEN_INFO OpenInfo
;
214 OpenInfo
= (PFONT_OPEN_INFO
) HeapAlloc( hProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(FONT_OPEN_INFO
) );
215 OpenInfo
->pszFileName
= HeapAlloc(hProcessHeap
, 0, MAX_PATH
);
216 if (OpenInfo
->pszFileName
)
218 OpenInfo
->pszFileName
[0] = 0;
220 if (DoOpenFile(OpenInfo
->pszFileName
))
222 OpenInfo
->bCreateNew
= FALSE
;
223 CreateFontWindow(Info
, OpenInfo
);
228 MessageBoxW(Info
->hMainWnd
, L
"Out of memory!", NULL
, MB_ICONERROR
);
233 MainWndOpenFile(IN PMAIN_WND_INFO Info
, LPCWSTR File
)
235 PFONT_OPEN_INFO OpenInfo
;
237 OpenInfo
= HeapAlloc(hProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(FONT_OPEN_INFO
));
238 OpenInfo
->pszFileName
= HeapAlloc(hProcessHeap
, 0, MAX_PATH
);
239 if (OpenInfo
->pszFileName
)
241 if (StringCchCopyW(OpenInfo
->pszFileName
, MAX_PATH
, File
) == S_OK
)
243 OpenInfo
->bCreateNew
= FALSE
;
244 CreateFontWindow(Info
, OpenInfo
);
248 MessageBoxW(Info
->hMainWnd
, L
"Pathname is too long!", NULL
, MB_ICONERROR
);
253 MessageBoxW(Info
->hMainWnd
, L
"Out of memory!", NULL
, MB_ICONERROR
);
258 MainWndDropFiles(IN PMAIN_WND_INFO Info
, HDROP hDrop
)
260 WCHAR Path
[MAX_PATH
];
261 INT i
, Count
= DragQueryFileW(hDrop
, 0xFFFFFFFF, NULL
, 0);
263 for (i
= 0; i
< Count
; ++i
)
265 DragQueryFileW(hDrop
, i
, Path
, MAX_PATH
);
266 MainWndOpenFile(Info
, Path
);
273 DoFileSave(IN PMAIN_WND_INFO Info
, IN BOOL bSaveAs
)
275 DWORD dwBytesWritten
;
278 // Show the "Save" dialog
279 // - if "Save As" was clicked
280 // - if the file was not yet saved
281 // - if another format than the binary format was opened
282 if(bSaveAs
|| !Info
->CurrentFontWnd
->OpenInfo
->bBinaryFileOpened
)
284 if(!Info
->CurrentFontWnd
->OpenInfo
->pszFileName
)
286 Info
->CurrentFontWnd
->OpenInfo
->pszFileName
= (PWSTR
) HeapAlloc(hProcessHeap
, 0, MAX_PATH
);
287 Info
->CurrentFontWnd
->OpenInfo
->pszFileName
[0] = 0;
289 else if(!Info
->CurrentFontWnd
->OpenInfo
->bBinaryFileOpened
)
291 // For a file in another format, the user has to enter a new file name as well
292 Info
->CurrentFontWnd
->OpenInfo
->pszFileName
[0] = 0;
295 if( !DoSaveFile(Info
->CurrentFontWnd
->OpenInfo
->pszFileName
) )
299 // Save the binary font
300 hFile
= CreateFileW(Info
->CurrentFontWnd
->OpenInfo
->pszFileName
, GENERIC_WRITE
, FILE_SHARE_WRITE
, NULL
, OPEN_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
302 if(hFile
== INVALID_HANDLE_VALUE
)
304 LocalizedError( IDS_OPENERROR
, GetLastError() );
308 if( !WriteFile(hFile
, Info
->CurrentFontWnd
->Font
, sizeof(BITMAP_FONT
), &dwBytesWritten
, NULL
) )
309 LocalizedError( IDS_WRITEERROR
, GetLastError() );
315 CopyCurrentGlyph(IN PFONT_WND_INFO FontWndInfo
)
318 PUCHAR pCharacterBits
;
320 if(!OpenClipboard(NULL
))
325 hMem
= GlobalAlloc(GMEM_MOVEABLE
, 8);
326 pCharacterBits
= GlobalLock(hMem
);
327 RtlCopyMemory(pCharacterBits
, FontWndInfo
->Font
->Bits
+ FontWndInfo
->uSelectedCharacter
* 8, 8);
330 SetClipboardData(uCharacterClipboardFormat
, hMem
);
336 PasteIntoCurrentGlyph(IN PFONT_WND_INFO FontWndInfo
)
340 if(!IsClipboardFormatAvailable(uCharacterClipboardFormat
))
343 if(!OpenClipboard(NULL
))
346 hMem
= GetClipboardData(uCharacterClipboardFormat
);
349 PUCHAR pCharacterBits
;
351 pCharacterBits
= GlobalLock(hMem
);
358 RtlCopyMemory(FontWndInfo
->Font
->Bits
+ FontWndInfo
->uSelectedCharacter
* 8, pCharacterBits
, 8);
361 FontWndInfo
->OpenInfo
->bModified
= TRUE
;
363 GetCharacterPosition(FontWndInfo
->uSelectedCharacter
, &uFontRow
, &uFontColumn
);
364 GetCharacterRect(uFontRow
, uFontColumn
, &CharacterRect
);
365 InvalidateRect(FontWndInfo
->hFontBoxesWnd
, &CharacterRect
, FALSE
);
373 SetPasteButtonState(IN PMAIN_WND_INFO Info
)
375 SetToolbarButtonState(Info
,
377 (Info
->CurrentFontWnd
&& IsClipboardFormatAvailable(uCharacterClipboardFormat
)));
381 MenuCommand(IN INT nMenuItemID
, IN PMAIN_WND_INFO Info
)
395 SendMessageW(Info
->CurrentFontWnd
->hSelf
, WM_CLOSE
, 0, 0);
399 DoFileSave(Info
, FALSE
);
402 case ID_FILE_SAVE_AS
:
403 DoFileSave(Info
, TRUE
);
407 PostMessage(Info
->hMainWnd
, WM_CLOSE
, 0, 0);
412 EditCurrentGlyph(Info
->CurrentFontWnd
);
416 CopyCurrentGlyph(Info
->CurrentFontWnd
);
420 PasteIntoCurrentGlyph(Info
->CurrentFontWnd
);
424 case ID_WINDOW_TILE_HORZ
:
425 SendMessageW(Info
->hMdiClient
, WM_MDITILE
, MDITILE_HORIZONTAL
, 0);
428 case ID_WINDOW_TILE_VERT
:
429 SendMessageW(Info
->hMdiClient
, WM_MDITILE
, MDITILE_VERTICAL
, 0);
432 case ID_WINDOW_CASCADE
:
433 SendMessageW(Info
->hMdiClient
, WM_MDICASCADE
, 0, 0);
436 case ID_WINDOW_ARRANGE
:
437 SendMessageW(Info
->hMdiClient
, WM_MDIICONARRANGE
, 0, 0);
441 SendMessageW(Info
->hMdiClient
, WM_MDINEXT
, 0, 0);
446 DialogBoxW( hInstance
, MAKEINTRESOURCEW(IDD_ABOUT
), Info
->hMainWnd
, AboutDlgProc
);
454 MainWndSize(PMAIN_WND_INFO Info
, INT cx
, INT cy
)
462 dwp
= BeginDeferWindowPos(2);
468 GetWindowRect(Info
->hToolbar
, &ToolbarRect
);
469 iMdiTop
+= ToolbarRect
.bottom
- ToolbarRect
.top
;
471 dwp
= DeferWindowPos(dwp
, Info
->hToolbar
, NULL
, 0, 0, cx
, ToolbarRect
.bottom
- ToolbarRect
.top
, SWP_NOZORDER
);
478 dwp
= DeferWindowPos(dwp
, Info
->hMdiClient
, NULL
, 0, iMdiTop
, cx
, cy
- iMdiTop
, SWP_NOZORDER
);
483 EndDeferWindowPos(dwp
);
486 static LRESULT CALLBACK
487 MainWndProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
489 static HWND hNextClipboardViewer
;
493 Info
= (PMAIN_WND_INFO
) GetWindowLongPtrW(hwnd
, GWLP_USERDATA
);
495 if(Info
|| uMsg
== WM_CREATE
)
500 if( MenuCommand( LOWORD(wParam
), Info
) )
505 case WM_CHANGECBCHAIN
:
506 if((HWND
)wParam
== hNextClipboardViewer
)
507 hNextClipboardViewer
= (HWND
)lParam
;
509 SendMessage(hNextClipboardViewer
, uMsg
, wParam
, lParam
);
514 if(Info
->FirstFontWnd
)
516 // Send WM_CLOSE to all subwindows, so they can prompt for saving unsaved files
517 PFONT_WND_INFO pNextWnd
;
520 pWnd
= Info
->FirstFontWnd
;
524 // The pWnd structure might already be destroyed after the WM_CLOSE, so we have to preserve the address of the next window here
525 pNextWnd
= pWnd
->NextFontWnd
;
527 // Send WM_USER_APPCLOSE, so we can check for a custom return value
528 // In this case, we check if the user clicked the "Cancel" button in one of the prompts and if so, we don't close the app
529 if( !SendMessage(pWnd
->hSelf
, WM_USER_APPCLOSE
, 0, 0) )
532 while( (pWnd
= pNextWnd
) );
537 Info
= (PMAIN_WND_INFO
)( ( (LPCREATESTRUCT
)lParam
)->lpCreateParams
);
538 Info
->hMainWnd
= hwnd
;
539 Info
->hMenu
= GetMenu(hwnd
);
540 SetWindowLongPtrW(hwnd
, GWLP_USERDATA
, (LONG_PTR
)Info
);
542 hNextClipboardViewer
= SetClipboardViewer(hwnd
);
547 ShowWindow(hwnd
, Info
->nCmdShow
);
549 for (i
= 1; i
< __argc
; ++i
)
551 MainWndOpenFile(Info
, __wargv
[i
]);
553 DragAcceptFiles(hwnd
, TRUE
);
557 UnInitResources(Info
);
559 HeapFree(hProcessHeap
, 0, Info
);
560 SetWindowLongPtrW(hwnd
, GWLP_USERDATA
, 0);
564 case WM_DRAWCLIPBOARD
:
565 SetPasteButtonState(Info
);
567 // Pass the message to the next clipboard window in the chain
568 SendMessage(hNextClipboardViewer
, uMsg
, wParam
, lParam
);
571 case WM_INITMENUPOPUP
:
576 MainWndSize( Info
, LOWORD(lParam
), HIWORD(lParam
) );
580 MainWndDropFiles(Info
, (HDROP
)wParam
);
585 if(Info
&& Info
->hMdiClient
)
586 return DefFrameProcW(hwnd
, Info
->hMdiClient
, uMsg
, wParam
, lParam
);
588 return DefWindowProcW(hwnd
, uMsg
, wParam
, lParam
);
592 CreateMainWindow(IN INT nCmdShow
, OUT PMAIN_WND_INFO
* Info
)
596 *Info
= (PMAIN_WND_INFO
) HeapAlloc( hProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(MAIN_WND_INFO
) );
600 (*Info
)->nCmdShow
= nCmdShow
;
602 hMainWnd
= CreateWindowExW(0,
605 WS_OVERLAPPEDWINDOW
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
,
611 LoadMenuW(hInstance
, MAKEINTRESOURCEW(IDM_MAINMENU
)),
618 HeapFree(hProcessHeap
, 0, *Info
);
625 InitMainWndClass(VOID
)
629 wc
.lpfnWndProc
= MainWndProc
;
630 wc
.hInstance
= hInstance
;
631 wc
.hCursor
= LoadCursor( NULL
, IDC_ARROW
);
632 wc
.hIcon
= LoadIconW( hInstance
, MAKEINTRESOURCEW(IDI_MAIN
) );
633 wc
.hbrBackground
= (HBRUSH
)( COLOR_BTNFACE
+ 1 );
634 wc
.lpszClassName
= szMainWndClass
;
636 return RegisterClassW(&wc
) != 0;
640 UnInitMainWndClass(VOID
)
642 UnregisterClassW(szMainWndClass
, hInstance
);