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 OutOfMemory(IN PMAIN_WND_INFO Info
)
201 MessageBoxW(Info
->hMainWnd
, L
"Out of memory!", NULL
, MB_ICONERROR
);
204 static PFONT_OPEN_INFO
205 CreateOpenInfo(IN PMAIN_WND_INFO Info
, BOOL bCreateNew
, LPCWSTR File
)
207 PFONT_OPEN_INFO OpenInfo
;
209 OpenInfo
= HeapAlloc(hProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(FONT_OPEN_INFO
));
216 OpenInfo
->bCreateNew
= bCreateNew
;
217 OpenInfo
->pszFileName
= HeapAlloc(hProcessHeap
, 0, MAX_PATH
);
218 if (!OpenInfo
->pszFileName
)
221 HeapFree(hProcessHeap
, 0, OpenInfo
);
225 if (StringCchCopyW(OpenInfo
->pszFileName
, MAX_PATH
, File
) != S_OK
)
227 MessageBoxW(Info
->hMainWnd
, L
"Pathname is too long!", NULL
, MB_ICONERROR
);
228 HeapFree(hProcessHeap
, 0, OpenInfo
->pszFileName
);
229 HeapFree(hProcessHeap
, 0, OpenInfo
);
237 DoFileNew(IN PMAIN_WND_INFO Info
)
239 PFONT_OPEN_INFO OpenInfo
= CreateOpenInfo(Info
, TRUE
, L
"");
243 CreateFontWindow(Info
, OpenInfo
);
247 DoFileOpen(IN PMAIN_WND_INFO Info
)
249 PFONT_OPEN_INFO OpenInfo
= CreateOpenInfo(Info
, FALSE
, L
"");
253 if (DoOpenFile(OpenInfo
->pszFileName
))
255 CreateFontWindow(Info
, OpenInfo
);
259 HeapFree(hProcessHeap
, 0, OpenInfo
->pszFileName
);
260 HeapFree(hProcessHeap
, 0, OpenInfo
);
264 MainWndOpenFile(IN PMAIN_WND_INFO Info
, LPCWSTR File
)
266 PFONT_OPEN_INFO OpenInfo
= CreateOpenInfo(Info
, FALSE
, File
);
270 CreateFontWindow(Info
, OpenInfo
);
274 MainWndDropFiles(IN PMAIN_WND_INFO Info
, HDROP hDrop
)
276 WCHAR Path
[MAX_PATH
];
277 INT i
, Count
= DragQueryFileW(hDrop
, 0xFFFFFFFF, NULL
, 0);
279 for (i
= 0; i
< Count
; ++i
)
281 DragQueryFileW(hDrop
, i
, Path
, MAX_PATH
);
282 MainWndOpenFile(Info
, Path
);
289 DoFileSave(IN PMAIN_WND_INFO Info
, IN BOOL bSaveAs
)
291 DWORD dwBytesWritten
;
294 // Show the "Save" dialog
295 // - if "Save As" was clicked
296 // - if the file was not yet saved
297 // - if another format than the binary format was opened
298 if(bSaveAs
|| !Info
->CurrentFontWnd
->OpenInfo
->bBinaryFileOpened
)
300 if(!Info
->CurrentFontWnd
->OpenInfo
->pszFileName
)
302 Info
->CurrentFontWnd
->OpenInfo
->pszFileName
= (PWSTR
) HeapAlloc(hProcessHeap
, 0, MAX_PATH
);
303 Info
->CurrentFontWnd
->OpenInfo
->pszFileName
[0] = 0;
305 else if(!Info
->CurrentFontWnd
->OpenInfo
->bBinaryFileOpened
)
307 // For a file in another format, the user has to enter a new file name as well
308 Info
->CurrentFontWnd
->OpenInfo
->pszFileName
[0] = 0;
311 if( !DoSaveFile(Info
->CurrentFontWnd
->OpenInfo
->pszFileName
) )
315 // Save the binary font
316 hFile
= CreateFileW(Info
->CurrentFontWnd
->OpenInfo
->pszFileName
, GENERIC_WRITE
, FILE_SHARE_WRITE
, NULL
, OPEN_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
318 if(hFile
== INVALID_HANDLE_VALUE
)
320 LocalizedError( IDS_OPENERROR
, GetLastError() );
324 if( !WriteFile(hFile
, Info
->CurrentFontWnd
->Font
, sizeof(BITMAP_FONT
), &dwBytesWritten
, NULL
) )
325 LocalizedError( IDS_WRITEERROR
, GetLastError() );
331 CopyCurrentGlyph(IN PFONT_WND_INFO FontWndInfo
)
334 PUCHAR pCharacterBits
;
336 if(!OpenClipboard(NULL
))
341 hMem
= GlobalAlloc(GMEM_MOVEABLE
, 8);
342 pCharacterBits
= GlobalLock(hMem
);
343 RtlCopyMemory(pCharacterBits
, FontWndInfo
->Font
->Bits
+ FontWndInfo
->uSelectedCharacter
* 8, 8);
346 SetClipboardData(uCharacterClipboardFormat
, hMem
);
352 PasteIntoCurrentGlyph(IN PFONT_WND_INFO FontWndInfo
)
356 if(!IsClipboardFormatAvailable(uCharacterClipboardFormat
))
359 if(!OpenClipboard(NULL
))
362 hMem
= GetClipboardData(uCharacterClipboardFormat
);
365 PUCHAR pCharacterBits
;
367 pCharacterBits
= GlobalLock(hMem
);
374 RtlCopyMemory(FontWndInfo
->Font
->Bits
+ FontWndInfo
->uSelectedCharacter
* 8, pCharacterBits
, 8);
377 FontWndInfo
->OpenInfo
->bModified
= TRUE
;
379 GetCharacterPosition(FontWndInfo
->uSelectedCharacter
, &uFontRow
, &uFontColumn
);
380 GetCharacterRect(uFontRow
, uFontColumn
, &CharacterRect
);
381 InvalidateRect(FontWndInfo
->hFontBoxesWnd
, &CharacterRect
, FALSE
);
389 SetPasteButtonState(IN PMAIN_WND_INFO Info
)
391 SetToolbarButtonState(Info
,
393 (Info
->CurrentFontWnd
&& IsClipboardFormatAvailable(uCharacterClipboardFormat
)));
397 MenuCommand(IN INT nMenuItemID
, IN PMAIN_WND_INFO Info
)
411 SendMessageW(Info
->CurrentFontWnd
->hSelf
, WM_CLOSE
, 0, 0);
415 DoFileSave(Info
, FALSE
);
418 case ID_FILE_SAVE_AS
:
419 DoFileSave(Info
, TRUE
);
423 PostMessage(Info
->hMainWnd
, WM_CLOSE
, 0, 0);
428 EditCurrentGlyph(Info
->CurrentFontWnd
);
432 CopyCurrentGlyph(Info
->CurrentFontWnd
);
436 PasteIntoCurrentGlyph(Info
->CurrentFontWnd
);
440 case ID_WINDOW_TILE_HORZ
:
441 SendMessageW(Info
->hMdiClient
, WM_MDITILE
, MDITILE_HORIZONTAL
, 0);
444 case ID_WINDOW_TILE_VERT
:
445 SendMessageW(Info
->hMdiClient
, WM_MDITILE
, MDITILE_VERTICAL
, 0);
448 case ID_WINDOW_CASCADE
:
449 SendMessageW(Info
->hMdiClient
, WM_MDICASCADE
, 0, 0);
452 case ID_WINDOW_ARRANGE
:
453 SendMessageW(Info
->hMdiClient
, WM_MDIICONARRANGE
, 0, 0);
457 SendMessageW(Info
->hMdiClient
, WM_MDINEXT
, 0, 0);
462 DialogBoxW( hInstance
, MAKEINTRESOURCEW(IDD_ABOUT
), Info
->hMainWnd
, AboutDlgProc
);
470 MainWndSize(PMAIN_WND_INFO Info
, INT cx
, INT cy
)
478 dwp
= BeginDeferWindowPos(2);
484 GetWindowRect(Info
->hToolbar
, &ToolbarRect
);
485 iMdiTop
+= ToolbarRect
.bottom
- ToolbarRect
.top
;
487 dwp
= DeferWindowPos(dwp
, Info
->hToolbar
, NULL
, 0, 0, cx
, ToolbarRect
.bottom
- ToolbarRect
.top
, SWP_NOZORDER
);
494 dwp
= DeferWindowPos(dwp
, Info
->hMdiClient
, NULL
, 0, iMdiTop
, cx
, cy
- iMdiTop
, SWP_NOZORDER
);
499 EndDeferWindowPos(dwp
);
502 static LRESULT CALLBACK
503 MainWndProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
505 static HWND hNextClipboardViewer
;
509 Info
= (PMAIN_WND_INFO
) GetWindowLongPtrW(hwnd
, GWLP_USERDATA
);
511 if(Info
|| uMsg
== WM_CREATE
)
516 if( MenuCommand( LOWORD(wParam
), Info
) )
521 case WM_CHANGECBCHAIN
:
522 if((HWND
)wParam
== hNextClipboardViewer
)
523 hNextClipboardViewer
= (HWND
)lParam
;
525 SendMessage(hNextClipboardViewer
, uMsg
, wParam
, lParam
);
530 if(Info
->FirstFontWnd
)
532 // Send WM_CLOSE to all subwindows, so they can prompt for saving unsaved files
533 PFONT_WND_INFO pNextWnd
;
536 pWnd
= Info
->FirstFontWnd
;
540 // The pWnd structure might already be destroyed after the WM_CLOSE, so we have to preserve the address of the next window here
541 pNextWnd
= pWnd
->NextFontWnd
;
543 // Send WM_USER_APPCLOSE, so we can check for a custom return value
544 // 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
545 if( !SendMessage(pWnd
->hSelf
, WM_USER_APPCLOSE
, 0, 0) )
548 while( (pWnd
= pNextWnd
) );
553 Info
= (PMAIN_WND_INFO
)( ( (LPCREATESTRUCT
)lParam
)->lpCreateParams
);
554 Info
->hMainWnd
= hwnd
;
555 Info
->hMenu
= GetMenu(hwnd
);
556 SetWindowLongPtrW(hwnd
, GWLP_USERDATA
, (LONG_PTR
)Info
);
558 hNextClipboardViewer
= SetClipboardViewer(hwnd
);
563 ShowWindow(hwnd
, Info
->nCmdShow
);
565 for (i
= 1; i
< __argc
; ++i
)
567 MainWndOpenFile(Info
, __wargv
[i
]);
569 DragAcceptFiles(hwnd
, TRUE
);
573 UnInitResources(Info
);
575 HeapFree(hProcessHeap
, 0, Info
);
576 SetWindowLongPtrW(hwnd
, GWLP_USERDATA
, 0);
580 case WM_DRAWCLIPBOARD
:
581 SetPasteButtonState(Info
);
583 // Pass the message to the next clipboard window in the chain
584 SendMessage(hNextClipboardViewer
, uMsg
, wParam
, lParam
);
587 case WM_INITMENUPOPUP
:
592 MainWndSize( Info
, LOWORD(lParam
), HIWORD(lParam
) );
596 MainWndDropFiles(Info
, (HDROP
)wParam
);
601 if(Info
&& Info
->hMdiClient
)
602 return DefFrameProcW(hwnd
, Info
->hMdiClient
, uMsg
, wParam
, lParam
);
604 return DefWindowProcW(hwnd
, uMsg
, wParam
, lParam
);
608 CreateMainWindow(IN INT nCmdShow
, OUT PMAIN_WND_INFO
* Info
)
612 *Info
= (PMAIN_WND_INFO
) HeapAlloc( hProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(MAIN_WND_INFO
) );
616 (*Info
)->nCmdShow
= nCmdShow
;
618 hMainWnd
= CreateWindowExW(0,
621 WS_OVERLAPPEDWINDOW
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
,
627 LoadMenuW(hInstance
, MAKEINTRESOURCEW(IDM_MAINMENU
)),
634 HeapFree(hProcessHeap
, 0, *Info
);
641 InitMainWndClass(VOID
)
645 wc
.lpfnWndProc
= MainWndProc
;
646 wc
.hInstance
= hInstance
;
647 wc
.hCursor
= LoadCursor( NULL
, IDC_ARROW
);
648 wc
.hIcon
= LoadIconW( hInstance
, MAKEINTRESOURCEW(IDI_MAIN
) );
649 wc
.hbrBackground
= (HBRUSH
)( COLOR_BTNFACE
+ 1 );
650 wc
.lpszClassName
= szMainWndClass
;
652 return RegisterClassW(&wc
) != 0;
656 UnInitMainWndClass(VOID
)
658 UnregisterClassW(szMainWndClass
, hInstance
);