2 * PROJECT: ReactOS VGA Font Editor
3 * LICENSE: GNU General Public License Version 2.0 or any later version
4 * FILE: devutils/vgafontedit/mainwnd.c
5 * PURPOSE: Implements the main window of the application
6 * COPYRIGHT: Copyright 2008 Colin Finck <mail@colinfinck.de>
11 static const WCHAR szMainWndClass
[] = L
"VGAFontEditMainWndClass";
14 InitResources(IN PMAIN_WND_INFO Info
)
21 hMemDC
= CreateCompatibleDC(NULL
);
22 hMainDC
= GetDC(Info
->hMainWnd
);
24 // Create the "Box" bitmap
25 Info
->hBoxBmp
= CreateCompatibleBitmap(hMainDC
, CHARACTER_BOX_WIDTH
, CHARACTER_BOX_HEIGHT
);
26 SelectObject(hMemDC
, Info
->hBoxBmp
);
30 rect
.right
= CHARACTER_INFO_BOX_WIDTH
;
31 rect
.bottom
= CHARACTER_INFO_BOX_HEIGHT
;
32 FillRect( hMemDC
, &rect
, (HBRUSH
)(COLOR_BTNFACE
+ 1) );
34 SelectObject( hMemDC
, GetStockObject(WHITE_PEN
) );
35 Rectangle(hMemDC
, 0, 0, CHARACTER_INFO_BOX_WIDTH
- 1, 2);
36 Rectangle(hMemDC
, 0, 2, 2, CHARACTER_INFO_BOX_HEIGHT
- 1);
38 hPen
= CreatePen( PS_SOLID
, 1, RGB(128, 128, 128) );
39 SelectObject(hMemDC
, hPen
);
40 Rectangle(hMemDC
, 1, CHARACTER_INFO_BOX_HEIGHT
- 2, CHARACTER_INFO_BOX_WIDTH
, CHARACTER_INFO_BOX_HEIGHT
);
41 Rectangle(hMemDC
, CHARACTER_INFO_BOX_WIDTH
- 2, 1, CHARACTER_INFO_BOX_WIDTH
, CHARACTER_INFO_BOX_HEIGHT
- 2);
43 SetPixel( hMemDC
, CHARACTER_INFO_BOX_WIDTH
- 1, 0, RGB(128, 128, 128) );
44 SetPixel( hMemDC
, 0, CHARACTER_INFO_BOX_HEIGHT
- 1, RGB(128, 128, 128) );
51 UnInitResources(IN PMAIN_WND_INFO Info
)
53 DeleteObject(Info
->hBoxBmp
);
57 AddToolbarButton(IN PMAIN_WND_INFO Info
, IN INT iBitmap
, IN INT idCommand
, IN UINT uID
)
62 if( AllocAndLoadString(&pszTooltip
, uID
) )
64 tbb
.fsState
= TBSTATE_ENABLED
;
65 tbb
.iBitmap
= iBitmap
;
66 tbb
.idCommand
= idCommand
;
67 tbb
.iString
= (INT_PTR
)pszTooltip
;
69 SendMessageW( Info
->hToolbar
, TB_ADDBUTTONSW
, 1, (LPARAM
)&tbb
);
70 HeapFree(hProcessHeap
, 0, pszTooltip
);
75 SetToolbarButtonState(IN PMAIN_WND_INFO Info
, INT idCommand
, BOOL bEnabled
)
77 TBBUTTONINFOW tbbi
= {0,};
79 tbbi
.cbSize
= sizeof(tbbi
);
80 tbbi
.dwMask
= TBIF_STATE
;
81 tbbi
.fsState
= (bEnabled
? TBSTATE_ENABLED
: 0);
83 SendMessageW(Info
->hToolbar
, TB_SETBUTTONINFOW
, idCommand
, (LPARAM
)&tbbi
);
87 SetToolbarFileButtonState(IN PMAIN_WND_INFO Info
, BOOL bEnabled
)
89 SetToolbarButtonState(Info
, ID_FILE_SAVE
, bEnabled
);
90 SetToolbarButtonState(Info
, ID_EDIT_GLYPH
, bEnabled
);
91 SetToolbarButtonState(Info
, ID_EDIT_COPY
, bEnabled
);
95 AddToolbarSeparator(IN PMAIN_WND_INFO Info
)
99 tbb
.fsStyle
= BTNS_SEP
;
101 SendMessageW( Info
->hToolbar
, TB_ADDBUTTONSW
, 1, (LPARAM
)&tbb
);
105 InitMainWnd(IN PMAIN_WND_INFO Info
)
107 CLIENTCREATESTRUCT ccs
;
109 INT iStandardBitmaps
;
113 Info
->hToolbar
= CreateWindowExW(0,
116 WS_VISIBLE
| WS_CHILD
| TBSTYLE_TOOLTIPS
,
126 // Identify the used Common Controls version
127 SendMessageW(Info
->hToolbar
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
130 SendMessageW(Info
->hToolbar
, TB_SETMAXTEXTROWS
, 0, 0);
132 // Add the toolbar bitmaps
133 tbab
.hInst
= HINST_COMMCTRL
;
134 tbab
.nID
= IDB_STD_SMALL_COLOR
;
135 iStandardBitmaps
= SendMessageW(Info
->hToolbar
, TB_ADDBITMAP
, 0, (LPARAM
)&tbab
);
137 tbab
.hInst
= hInstance
;
138 tbab
.nID
= IDB_MAIN_TOOLBAR
;
139 iCustomBitmaps
= SendMessageW(Info
->hToolbar
, TB_ADDBITMAP
, 0, (LPARAM
)&tbab
);
141 // Add the toolbar buttons
142 AddToolbarButton(Info
, iStandardBitmaps
+ STD_FILENEW
, ID_FILE_NEW
, IDS_TOOLTIP_NEW
);
143 AddToolbarButton(Info
, iStandardBitmaps
+ STD_FILEOPEN
, ID_FILE_OPEN
, IDS_TOOLTIP_OPEN
);
144 AddToolbarButton(Info
, iStandardBitmaps
+ STD_FILESAVE
, ID_FILE_SAVE
, IDS_TOOLTIP_SAVE
);
145 AddToolbarSeparator(Info
);
146 AddToolbarButton(Info
, iCustomBitmaps
+ TOOLBAR_EDIT_GLYPH
, ID_EDIT_GLYPH
, IDS_TOOLTIP_EDIT_GLYPH
);
147 AddToolbarSeparator(Info
);
148 AddToolbarButton(Info
, iStandardBitmaps
+ STD_COPY
, ID_EDIT_COPY
, IDS_TOOLTIP_COPY
);
149 AddToolbarButton(Info
, iStandardBitmaps
+ STD_PASTE
, ID_EDIT_PASTE
, IDS_TOOLTIP_PASTE
);
151 SetToolbarFileButtonState(Info
, FALSE
);
152 SetPasteButtonState(Info
);
154 // Add the MDI client area
155 ccs
.hWindowMenu
= GetSubMenu(Info
->hMenu
, 2);
156 ccs
.idFirstChild
= ID_MDI_FIRSTCHILD
;
158 Info
->hMdiClient
= CreateWindowExW(WS_EX_CLIENTEDGE
,
161 WS_VISIBLE
| WS_CHILD
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
| WS_VSCROLL
| WS_HSCROLL
,
171 // Initialize the file handling
172 FileInitialize(Info
->hMainWnd
);
176 InitMenuPopup(IN PMAIN_WND_INFO Info
)
180 uState
= MF_BYCOMMAND
| !(Info
->CurrentFontWnd
);
182 EnableMenuItem(Info
->hMenu
, ID_FILE_CLOSE
, uState
);
183 EnableMenuItem(Info
->hMenu
, ID_FILE_SAVE
, uState
);
184 EnableMenuItem(Info
->hMenu
, ID_FILE_SAVE_AS
, uState
);
186 EnableMenuItem(Info
->hMenu
, ID_EDIT_COPY
, uState
);
187 EnableMenuItem(Info
->hMenu
, ID_EDIT_GLYPH
, uState
);
189 uState
= MF_BYCOMMAND
| !(Info
->CurrentFontWnd
&& IsClipboardFormatAvailable(uCharacterClipboardFormat
));
190 EnableMenuItem(Info
->hMenu
, ID_EDIT_PASTE
, uState
);
194 DoFileNew(IN PMAIN_WND_INFO Info
)
196 PFONT_OPEN_INFO OpenInfo
;
198 OpenInfo
= (PFONT_OPEN_INFO
) HeapAlloc( hProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(FONT_OPEN_INFO
) );
199 OpenInfo
->bCreateNew
= TRUE
;
201 CreateFontWindow(Info
, OpenInfo
);
205 DoFileOpen(IN PMAIN_WND_INFO Info
)
207 PFONT_OPEN_INFO OpenInfo
;
209 OpenInfo
= (PFONT_OPEN_INFO
) HeapAlloc( hProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(FONT_OPEN_INFO
) );
210 OpenInfo
->pszFileName
= HeapAlloc(hProcessHeap
, 0, MAX_PATH
);
211 OpenInfo
->pszFileName
[0] = 0;
213 if( DoOpenFile(OpenInfo
->pszFileName
) )
215 OpenInfo
->bCreateNew
= FALSE
;
216 CreateFontWindow(Info
, OpenInfo
);
221 DoFileSave(IN PMAIN_WND_INFO Info
, IN BOOL bSaveAs
)
223 DWORD dwBytesWritten
;
226 // Show the "Save" dialog
227 // - if "Save As" was clicked
228 // - if the file was not yet saved
229 // - if another format than the binary format was opened
230 if(bSaveAs
|| !Info
->CurrentFontWnd
->OpenInfo
->bBinaryFileOpened
)
232 if(!Info
->CurrentFontWnd
->OpenInfo
->pszFileName
)
234 Info
->CurrentFontWnd
->OpenInfo
->pszFileName
= (PWSTR
) HeapAlloc(hProcessHeap
, 0, MAX_PATH
);
235 Info
->CurrentFontWnd
->OpenInfo
->pszFileName
[0] = 0;
237 else if(!Info
->CurrentFontWnd
->OpenInfo
->bBinaryFileOpened
)
239 // For a file in another format, the user has to enter a new file name as well
240 Info
->CurrentFontWnd
->OpenInfo
->pszFileName
[0] = 0;
243 if( !DoSaveFile(Info
->CurrentFontWnd
->OpenInfo
->pszFileName
) )
247 // Save the binary font
248 hFile
= CreateFileW(Info
->CurrentFontWnd
->OpenInfo
->pszFileName
, GENERIC_WRITE
, FILE_SHARE_WRITE
, NULL
, OPEN_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
250 if(hFile
== INVALID_HANDLE_VALUE
)
252 LocalizedError( IDS_OPENERROR
, GetLastError() );
256 if( !WriteFile(hFile
, Info
->CurrentFontWnd
->Font
, sizeof(BITMAP_FONT
), &dwBytesWritten
, NULL
) )
257 LocalizedError( IDS_WRITEERROR
, GetLastError() );
263 CopyCurrentGlyph(IN PFONT_WND_INFO FontWndInfo
)
266 PUCHAR pCharacterBits
;
268 if(!OpenClipboard(NULL
))
273 hMem
= GlobalAlloc(GMEM_MOVEABLE
, 8);
274 pCharacterBits
= GlobalLock(hMem
);
275 RtlCopyMemory(pCharacterBits
, FontWndInfo
->Font
->Bits
+ FontWndInfo
->uSelectedCharacter
* 8, 8);
278 SetClipboardData(uCharacterClipboardFormat
, hMem
);
284 PasteIntoCurrentGlyph(IN PFONT_WND_INFO FontWndInfo
)
288 if(!IsClipboardFormatAvailable(uCharacterClipboardFormat
))
291 if(!OpenClipboard(NULL
))
294 hMem
= GetClipboardData(uCharacterClipboardFormat
);
297 PUCHAR pCharacterBits
;
299 pCharacterBits
= GlobalLock(hMem
);
306 RtlCopyMemory(FontWndInfo
->Font
->Bits
+ FontWndInfo
->uSelectedCharacter
* 8, pCharacterBits
, 8);
309 FontWndInfo
->OpenInfo
->bModified
= TRUE
;
311 GetCharacterPosition(FontWndInfo
->uSelectedCharacter
, &uFontRow
, &uFontColumn
);
312 GetCharacterRect(uFontRow
, uFontColumn
, &CharacterRect
);
313 InvalidateRect(FontWndInfo
->hFontBoxesWnd
, &CharacterRect
, FALSE
);
321 SetPasteButtonState(IN PMAIN_WND_INFO Info
)
323 SetToolbarButtonState(Info
,
325 (Info
->CurrentFontWnd
&& IsClipboardFormatAvailable(uCharacterClipboardFormat
)));
329 MenuCommand(IN INT nMenuItemID
, IN PMAIN_WND_INFO Info
)
343 SendMessageW(Info
->CurrentFontWnd
->hSelf
, WM_CLOSE
, 0, 0);
347 DoFileSave(Info
, FALSE
);
350 case ID_FILE_SAVE_AS
:
351 DoFileSave(Info
, TRUE
);
355 PostMessage(Info
->hMainWnd
, WM_CLOSE
, 0, 0);
360 EditCurrentGlyph(Info
->CurrentFontWnd
);
364 CopyCurrentGlyph(Info
->CurrentFontWnd
);
368 PasteIntoCurrentGlyph(Info
->CurrentFontWnd
);
372 case ID_WINDOW_TILE_HORZ
:
373 SendMessageW(Info
->hMdiClient
, WM_MDITILE
, MDITILE_HORIZONTAL
, 0);
376 case ID_WINDOW_TILE_VERT
:
377 SendMessageW(Info
->hMdiClient
, WM_MDITILE
, MDITILE_VERTICAL
, 0);
380 case ID_WINDOW_CASCADE
:
381 SendMessageW(Info
->hMdiClient
, WM_MDICASCADE
, 0, 0);
384 case ID_WINDOW_ARRANGE
:
385 SendMessageW(Info
->hMdiClient
, WM_MDIICONARRANGE
, 0, 0);
389 SendMessageW(Info
->hMdiClient
, WM_MDINEXT
, 0, 0);
394 DialogBoxW( hInstance
, MAKEINTRESOURCEW(IDD_ABOUT
), Info
->hMainWnd
, AboutDlgProc
);
402 MainWndSize(PMAIN_WND_INFO Info
, INT cx
, INT cy
)
410 dwp
= BeginDeferWindowPos(2);
416 GetWindowRect(Info
->hToolbar
, &ToolbarRect
);
417 iMdiTop
+= ToolbarRect
.bottom
- ToolbarRect
.top
;
419 dwp
= DeferWindowPos(dwp
, Info
->hToolbar
, NULL
, 0, 0, cx
, ToolbarRect
.bottom
- ToolbarRect
.top
, SWP_NOZORDER
);
426 dwp
= DeferWindowPos(dwp
, Info
->hMdiClient
, NULL
, 0, iMdiTop
, cx
, cy
- iMdiTop
, SWP_NOZORDER
);
431 EndDeferWindowPos(dwp
);
434 static LRESULT CALLBACK
435 MainWndProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
437 static HWND hNextClipboardViewer
;
441 Info
= (PMAIN_WND_INFO
) GetWindowLongW(hwnd
, GWLP_USERDATA
);
443 if(Info
|| uMsg
== WM_CREATE
)
448 if( MenuCommand( LOWORD(wParam
), Info
) )
453 case WM_CHANGECBCHAIN
:
454 if((HWND
)wParam
== hNextClipboardViewer
)
455 hNextClipboardViewer
= (HWND
)lParam
;
457 SendMessage(hNextClipboardViewer
, uMsg
, wParam
, lParam
);
462 if(Info
->FirstFontWnd
)
464 // Send WM_CLOSE to all subwindows, so they can prompt for saving unsaved files
465 PFONT_WND_INFO pNextWnd
;
468 pWnd
= Info
->FirstFontWnd
;
472 // The pWnd structure might already be destroyed after the WM_CLOSE, so we have to preserve the address of the next window here
473 pNextWnd
= pWnd
->NextFontWnd
;
475 // Send WM_USER_APPCLOSE, so we can check for a custom return value
476 // 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
477 if( !SendMessage(pWnd
->hSelf
, WM_USER_APPCLOSE
, 0, 0) )
480 while( (pWnd
= pNextWnd
) );
485 Info
= (PMAIN_WND_INFO
)( ( (LPCREATESTRUCT
)lParam
)->lpCreateParams
);
486 Info
->hMainWnd
= hwnd
;
487 Info
->hMenu
= GetMenu(hwnd
);
488 SetWindowLongW(hwnd
, GWLP_USERDATA
, (LONG
)Info
);
490 hNextClipboardViewer
= SetClipboardViewer(hwnd
);
495 ShowWindow(hwnd
, Info
->nCmdShow
);
499 UnInitResources(Info
);
501 HeapFree(hProcessHeap
, 0, Info
);
502 SetWindowLongW(hwnd
, GWLP_USERDATA
, 0);
506 case WM_DRAWCLIPBOARD
:
507 SetPasteButtonState(Info
);
509 // Pass the message to the next clipboard window in the chain
510 SendMessage(hNextClipboardViewer
, uMsg
, wParam
, lParam
);
513 case WM_INITMENUPOPUP
:
518 MainWndSize( Info
, LOWORD(lParam
), HIWORD(lParam
) );
523 if(Info
&& Info
->hMdiClient
)
524 return DefFrameProcW(hwnd
, Info
->hMdiClient
, uMsg
, wParam
, lParam
);
526 return DefWindowProcW(hwnd
, uMsg
, wParam
, lParam
);
530 CreateMainWindow(IN INT nCmdShow
, OUT PMAIN_WND_INFO
* Info
)
534 *Info
= (PMAIN_WND_INFO
) HeapAlloc( hProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(MAIN_WND_INFO
) );
538 (*Info
)->nCmdShow
= nCmdShow
;
540 hMainWnd
= CreateWindowExW(0,
543 WS_OVERLAPPEDWINDOW
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
,
549 LoadMenuW(hInstance
, MAKEINTRESOURCEW(IDM_MAINMENU
)),
556 HeapFree(hProcessHeap
, 0, *Info
);
563 InitMainWndClass(VOID
)
567 wc
.lpfnWndProc
= MainWndProc
;
568 wc
.hInstance
= hInstance
;
569 wc
.hCursor
= LoadCursor( NULL
, IDC_ARROW
);
570 wc
.hIcon
= LoadIconW( hInstance
, MAKEINTRESOURCEW(IDI_MAIN
) );
571 wc
.hbrBackground
= (HBRUSH
)( COLOR_BTNFACE
+ 1 );
572 wc
.lpszClassName
= szMainWndClass
;
574 return RegisterClassW(&wc
) != 0;
578 UnInitMainWndClass(VOID
)
580 UnregisterClassW(szMainWndClass
, hInstance
);