[CHARMAP]
[reactos.git] / reactos / base / applications / charmap_new / MainWindow.cpp
1 /*
2 * PROJECT: ReactOS Character Map
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/charmap/MainWindow.cpp
5 * PURPOSE: Implements the main dialog window
6 * COPYRIGHT: Copyright 2015 Ged Murphy <gedmurphy@reactos.org>
7 */
8
9
10 #include "precomp.h"
11 #include "MainWindow.h"
12
13
14 /* DATA *****************************************************/
15
16 #define ID_ABOUT 0x1
17
18 HINSTANCE g_hInstance = NULL;
19
20
21 /* PUBLIC METHODS **********************************************/
22
23 CCharMapWindow::CCharMapWindow(void) :
24 m_hMainWnd(NULL),
25 m_hStatusBar(NULL),
26 m_CmdShow(0),
27 m_hRichEd(NULL),
28 m_GridView(nullptr)
29 {
30 m_GridView = new CGridView();
31 }
32
33 CCharMapWindow::~CCharMapWindow(void)
34 {
35 }
36
37 bool
38 CCharMapWindow::Create(_In_ HINSTANCE hInst,
39 _In_ int nCmdShow)
40 {
41 INITCOMMONCONTROLSEX icex;
42 CAtlStringW szAppName;
43 int Ret = 1;
44
45 // Store the instance
46 g_hInstance = hInst;
47 m_CmdShow = nCmdShow;
48
49 // Initialize common controls
50 icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
51 icex.dwICC = ICC_BAR_CLASSES | ICC_COOL_CLASSES;
52 InitCommonControlsEx(&icex);
53
54 // Load the application name
55 if (szAppName.LoadStringW(g_hInstance, IDS_TITLE))
56 {
57 // Initialize the main window
58 if (Initialize(szAppName, nCmdShow))
59 {
60 // Run the application
61 Ret = Run();
62
63 // Uninitialize the main window
64 Uninitialize();
65 }
66 }
67
68 return (Ret == 0);
69 }
70
71
72
73 /* PRIVATE METHODS **********************************************/
74
75 bool
76 CCharMapWindow::Initialize(_In_z_ LPCTSTR lpCaption,
77 _In_ int nCmdShow)
78 {
79 // The dialog has a rich edit text box
80 m_hRichEd = LoadLibraryW(L"riched20.DLL");
81 if (m_hRichEd == NULL) return false;
82
83 return !!(CreateDialogParamW(g_hInstance,
84 MAKEINTRESOURCE(IDD_CHARMAP),
85 NULL,
86 DialogProc,
87 (LPARAM)this));
88 }
89
90 void
91 CCharMapWindow::Uninitialize(void)
92 {
93 if (m_hRichEd)
94 FreeLibrary(m_hRichEd);
95 }
96
97 int
98 CCharMapWindow::Run(void)
99 {
100 MSG Msg;
101
102 // Pump the message queue
103 while (GetMessageW(&Msg, NULL, 0, 0) != 0)
104 {
105 TranslateMessage(&Msg);
106 DispatchMessageW(&Msg);
107 }
108
109 return 0;
110 }
111
112 void
113 CCharMapWindow::UpdateStatusBar(_In_ bool InMenuLoop)
114 {
115 SendMessageW(m_hStatusBar,
116 SB_SIMPLE,
117 (WPARAM)InMenuLoop,
118 0);
119 }
120
121 bool
122 CCharMapWindow::CreateStatusBar(void)
123 {
124 int StatWidths[] = { 110, -1 }; // widths of status bar
125 bool bRet = FALSE;
126
127 // Create the status bar
128 m_hStatusBar = CreateWindowExW(0,
129 STATUSCLASSNAME,
130 NULL,
131 WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
132 0, 0, 0, 0,
133 m_hMainWnd,
134 (HMENU)IDD_STATUSBAR,
135 g_hInstance,
136 NULL);
137 if (m_hStatusBar)
138 {
139 // Create the sections
140 bRet = (SendMessageW(m_hStatusBar,
141 SB_SETPARTS,
142 sizeof(StatWidths) / sizeof(int),
143 (LPARAM)StatWidths) != 0);
144
145 // Set the status bar for multiple parts output
146 SendMessage(m_hStatusBar, SB_SIMPLE, (WPARAM)FALSE, (LPARAM)0);
147 }
148
149 return bRet;
150 }
151
152 bool
153 CCharMapWindow::StatusBarLoadString(_In_ HWND hStatusBar,
154 _In_ INT PartId,
155 _In_ HINSTANCE hInstance,
156 _In_ UINT uID)
157 {
158 CAtlStringW szMessage;
159 bool bRet = false;
160
161 // Load the string from the resource
162 if (szMessage.LoadStringW(hInstance, uID))
163 {
164 // Display it on the status bar
165 bRet = (SendMessageW(hStatusBar,
166 SB_SETTEXT,
167 (WPARAM)PartId,
168 (LPARAM)szMessage.GetBuffer()) != 0);
169 }
170
171 return bRet;
172 }
173
174 BOOL
175 CCharMapWindow::OnCreate(_In_ HWND hDlg)
176 {
177 m_hMainWnd = hDlg;
178
179 if (!CreateStatusBar())
180 return FALSE;
181
182 if (!m_GridView->Create(hDlg))
183 return FALSE;
184
185 // Load an 'about' option into the system menu
186 HMENU hSysMenu;
187 hSysMenu = GetSystemMenu(m_hMainWnd, FALSE);
188 if (hSysMenu != NULL)
189 {
190 CAtlStringW AboutText;
191 if (AboutText.LoadStringW(IDS_ABOUT))
192 {
193 AppendMenuW(hSysMenu, MF_SEPARATOR, 0, NULL);
194 AppendMenuW(hSysMenu, MF_STRING, ID_ABOUT, AboutText);
195 }
196 }
197
198 // Add all the fonts to the
199 if (!CreateFontComboBox())
200 return FALSE;
201
202 // Configure Richedit control for sending notification changes.
203 DWORD evMask;
204 evMask = SendDlgItemMessage(hDlg, IDC_TEXTBOX, EM_GETEVENTMASK, 0, 0);
205 evMask |= ENM_CHANGE;
206 SendDlgItemMessage(hDlg, IDC_TEXTBOX, EM_SETEVENTMASK, 0, (LPARAM)evMask);
207
208 // Display the window according to the user request
209 ShowWindow(m_hMainWnd, m_CmdShow);
210
211 return TRUE;
212 }
213
214 BOOL
215 CCharMapWindow::OnSize(void)
216 {
217 RECT rcClient, rcStatus;
218 INT lvHeight, iStatusHeight;
219
220 // Resize the status bar
221 SendMessage(m_hStatusBar, WM_SIZE, 0, 0);
222
223 // Get the statusbar rect and save the height
224 GetWindowRect(m_hStatusBar, &rcStatus);
225 iStatusHeight = rcStatus.bottom - rcStatus.top;
226
227 // Get the full client rect
228 GetClientRect(m_hMainWnd, &rcClient);
229
230 // Calculate the remaining height for the treeview
231 lvHeight = rcClient.bottom - iStatusHeight;
232
233 // Resize the device view
234 //m_GridView->OnSize(0,
235 // iToolHeight,
236 // rcClient.right,
237 // lvHeight);
238
239 return TRUE;
240 }
241
242 BOOL
243 CCharMapWindow::OnNotify(_In_ LPARAM lParam)
244 {
245 LPNMHDR NmHdr = (LPNMHDR)lParam;
246 LRESULT Ret = 0;
247
248 switch (NmHdr->code)
249 {
250 case NM_RCLICK:
251 {
252 break;
253 }
254
255 case NM_DBLCLK:
256 case NM_RETURN:
257 {
258 break;
259 }
260 }
261
262 return Ret;
263 }
264
265 BOOL
266 CCharMapWindow::OnContext(_In_ LPARAM lParam)
267 {
268 return 0;// m_GridView->OnContextMenu(lParam);
269 }
270
271 BOOL
272 CCharMapWindow::OnCommand(_In_ WPARAM wParam,
273 _In_ LPARAM /*lParam*/)
274 {
275 LRESULT RetCode = 0;
276 WORD Msg;
277
278 // Get the message
279 Msg = LOWORD(wParam);
280
281 switch (Msg)
282 {
283 case IDC_CHECK_ADVANCED:
284 break;
285
286 default:
287 // We didn't handle it
288 RetCode = -1;
289 break;
290 }
291
292 return RetCode;
293 }
294
295 BOOL
296 CCharMapWindow::OnDestroy(void)
297 {
298 // Clear the user data pointer
299 SetWindowLongPtr(m_hMainWnd, GWLP_USERDATA, 0);
300
301 // Break the message loop
302 PostQuitMessage(0);
303
304 return TRUE;
305 }
306
307 INT_PTR CALLBACK
308 CCharMapWindow::DialogProc(
309 _In_ HWND hwndDlg,
310 _In_ UINT Msg,
311 _In_ WPARAM wParam,
312 _In_ LPARAM lParam
313 )
314 {
315 CCharMapWindow *This;
316 LRESULT RetCode = 0;
317
318 // Get the object pointer from window context
319 This = (CCharMapWindow *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
320 if (This == NULL)
321 {
322 // Check that this isn't a create message
323 if (Msg != WM_INITDIALOG)
324 {
325 // Don't handle null info pointer
326 return FALSE;
327 }
328 }
329
330 switch (Msg)
331 {
332 case WM_INITDIALOG:
333 {
334 // Get the object pointer from the create param
335 This = (CCharMapWindow *)lParam;
336
337 // Store the pointer in the window's global user data
338 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)This);
339
340 // Call the create handler
341 return This->OnCreate(hwndDlg);
342 }
343
344 case WM_SIZE:
345 {
346 return This->OnSize();
347 }
348
349 case WM_NOTIFY:
350 {
351 return This->OnNotify(lParam);
352 }
353
354 case WM_CONTEXTMENU:
355 {
356 return This->OnContext(lParam);
357 }
358
359 case WM_COMMAND:
360 {
361 return This->OnCommand(wParam, lParam);
362 }
363
364 case WM_SYSCOMMAND:
365 switch (wParam)
366 {
367 case ID_ABOUT:
368 // Apportion blame
369 MessageBoxW(This->m_hMainWnd,
370 L"ReactOS Character Map\r\nCopyright Ged Murphy 2015",
371 L"About",
372 MB_OK | MB_APPLMODAL);
373 break;
374 }
375 break;
376
377 case WM_ENTERMENULOOP:
378 {
379 This->UpdateStatusBar(true);
380 return TRUE;
381 }
382
383 case WM_EXITMENULOOP:
384 {
385 This->UpdateStatusBar(false);
386 return TRUE;
387 }
388
389 case WM_CLOSE:
390 {
391 // Destroy the main window
392 return DestroyWindow(hwndDlg);
393 }
394
395
396 case WM_DESTROY:
397 {
398 // Call the destroy handler
399 return This->OnDestroy();
400 }
401 }
402
403 return FALSE;
404 }
405
406 struct EnumFontParams
407 {
408 CCharMapWindow *This;
409 HWND hCombo;
410 };
411
412 int
413 CALLBACK
414 CCharMapWindow::EnumDisplayFont(ENUMLOGFONTEXW *lpelfe,
415 NEWTEXTMETRICEXW *lpntme,
416 DWORD FontType,
417 LPARAM lParam)
418 {
419 EnumFontParams *Params = (EnumFontParams *)lParam;
420 LPWSTR pszName = lpelfe->elfLogFont.lfFaceName;
421
422 /* Skip rotated font */
423 if (pszName[0] == L'@') return 1;
424
425 /* make sure font doesn't already exist in our list */
426 if (SendMessageW(Params->hCombo,
427 CB_FINDSTRINGEXACT,
428 0,
429 (LPARAM)pszName) == CB_ERR)
430 {
431 INT idx;
432 idx = (INT)SendMessageW(Params->hCombo,
433 CB_ADDSTRING,
434 0,
435 (LPARAM)pszName);
436
437 /* record the font's attributes (Fixedwidth and Truetype) */
438 BOOL fFixed = (lpelfe->elfLogFont.lfPitchAndFamily & FIXED_PITCH) ? TRUE : FALSE;
439 BOOL fTrueType = (lpelfe->elfLogFont.lfOutPrecision == OUT_STROKE_PRECIS) ? TRUE : FALSE;
440
441 /* store this information in the list-item's userdata area */
442 SendMessageW(Params->hCombo,
443 CB_SETITEMDATA,
444 idx,
445 MAKEWPARAM(fFixed, fTrueType));
446 }
447
448 return 1;
449 }
450
451
452 bool
453 CCharMapWindow::CreateFontComboBox()
454 {
455 HWND hCombo;
456 hCombo = GetDlgItem(m_hMainWnd, IDC_FONTCOMBO);
457
458 NONCLIENTMETRICSW NonClientMetrics;
459 NonClientMetrics.cbSize = sizeof(NONCLIENTMETRICSW);
460 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
461 sizeof(NONCLIENTMETRICSW),
462 &NonClientMetrics,
463 0);
464
465 // Get a handle to the font
466 HFONT GuiFont;
467 GuiFont = CreateFontIndirectW(&NonClientMetrics.lfMessageFont);
468
469 // Set the font used in the combo box
470 SendMessageW(hCombo,
471 WM_SETFONT,
472 (WPARAM)GuiFont,
473 0);
474
475 // Set the fonts which we want to enumerate
476 LOGFONTW FontsToEnum;
477 ZeroMemory(&FontsToEnum, sizeof(LOGFONTW));
478 FontsToEnum.lfCharSet = DEFAULT_CHARSET;
479
480 // Set the params we want to pass to the callback
481 EnumFontParams Params;
482 Params.This = this;
483 Params.hCombo = hCombo;
484
485 // Get a DC for combo box
486 HDC hdc;
487 hdc = GetDC(hCombo);
488
489 // Enumerate all the fonts
490 int ret;
491 ret = EnumFontFamiliesExW(hdc,
492 &FontsToEnum,
493 (FONTENUMPROCW)EnumDisplayFont,
494 (LPARAM)&Params,
495 0);
496
497 ReleaseDC(hCombo, hdc);
498 DeleteObject(GuiFont);
499
500 // Select the first item in the list
501 SendMessageW(hCombo,
502 CB_SETCURSEL,
503 0,
504 0);
505
506 return (ret == 1);
507 }