33d73517124d573397511ddf971b0225f5e9c120
[reactos.git] / reactos / base / applications / charmap / charmap.c
1 /*
2 * PROJECT: ReactOS Character Map
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/charmap/charmap.c
5 * PURPOSE: main dialog implementation
6 * COPYRIGHT: Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
7 *
8 */
9
10 #include <precomp.h>
11
12 #define ID_ABOUT 0x1
13
14 HINSTANCE hInstance;
15 HWND hAdvancedDlg;
16 HWND hStatusWnd;
17 HICON hSmIcon;
18 HICON hBgIcon;
19
20 /* Font-enumeration callback */
21 static
22 int
23 CALLBACK
24 EnumFontNames(ENUMLOGFONTEXW *lpelfe,
25 NEWTEXTMETRICEXW *lpntme,
26 DWORD FontType,
27 LPARAM lParam)
28 {
29 HWND hwndCombo = (HWND)lParam;
30 LPWSTR pszName = lpelfe->elfLogFont.lfFaceName;
31
32 /* make sure font doesn't already exist in our list */
33 if(SendMessageW(hwndCombo,
34 CB_FINDSTRING,
35 0,
36 (LPARAM)pszName) == CB_ERR)
37 {
38 INT idx;
39 BOOL fFixed;
40 BOOL fTrueType;
41
42 /* add the font */
43 idx = (INT)SendMessageW(hwndCombo,
44 CB_ADDSTRING,
45 0,
46 (LPARAM)pszName);
47
48 /* record the font's attributes (Fixedwidth and Truetype) */
49 fFixed = (lpelfe->elfLogFont.lfPitchAndFamily & FIXED_PITCH) ? TRUE : FALSE;
50 fTrueType = (lpelfe->elfLogFont.lfOutPrecision == OUT_STROKE_PRECIS) ? TRUE : FALSE;
51
52 /* store this information in the list-item's userdata area */
53 SendMessageW(hwndCombo,
54 CB_SETITEMDATA,
55 idx,
56 MAKEWPARAM(fFixed, fTrueType));
57 }
58
59 return 1;
60 }
61
62
63 /* Initialize the font-list by enumeration all system fonts */
64 static
65 VOID
66 FillFontStyleComboList(HWND hwndCombo)
67 {
68 HDC hdc;
69 LOGFONTW lf;
70
71 /* FIXME: for fun, draw each font in its own style */
72 HFONT hFont = GetStockObject(DEFAULT_GUI_FONT);
73 SendMessageW(hwndCombo,
74 WM_SETFONT,
75 (WPARAM)hFont,
76 0);
77
78 ZeroMemory(&lf, sizeof(lf));
79 lf.lfCharSet = DEFAULT_CHARSET;
80
81 hdc = GetDC(hwndCombo);
82
83 /* store the list of fonts in the combo */
84 EnumFontFamiliesExW(hdc,
85 &lf,
86 (FONTENUMPROCW)EnumFontNames,
87 (LPARAM)hwndCombo,
88 0);
89
90 ReleaseDC(hwndCombo,
91 hdc);
92
93 SendMessageW(hwndCombo,
94 CB_SETCURSEL,
95 0,
96 0);
97 }
98
99
100 extern
101 VOID
102 ChangeMapFont(HWND hDlg)
103 {
104 HWND hCombo;
105 HWND hMap;
106 LPWSTR lpFontName;
107 INT Len;
108
109 hCombo = GetDlgItem(hDlg, IDC_FONTCOMBO);
110
111 Len = GetWindowTextLengthW(hCombo);
112
113 if (Len != 0)
114 {
115 lpFontName = HeapAlloc(GetProcessHeap(),
116 0,
117 (Len + 1) * sizeof(WCHAR));
118
119 if (lpFontName)
120 {
121 SendMessageW(hCombo,
122 WM_GETTEXT,
123 Len + 1,
124 (LPARAM)lpFontName);
125
126 hMap = GetDlgItem(hDlg, IDC_FONTMAP);
127
128 SendMessageW(hMap,
129 FM_SETFONT,
130 0,
131 (LPARAM)lpFontName);
132 }
133
134 HeapFree(GetProcessHeap(),
135 0,
136 lpFontName);
137 }
138 }
139
140 // Copy collected characters into the clipboard
141 static
142 void
143 CopyCharacters(HWND hDlg)
144 {
145 HWND hText = GetDlgItem(hDlg, IDC_TEXTBOX);
146 DWORD dwStart, dwEnd;
147
148 // Acquire selection limits
149 SendMessage(hText, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
150
151 // Test if the whose text is unselected
152 if(dwStart == dwEnd) {
153
154 // Select the whole text
155 SendMessageW(hText, EM_SETSEL, 0, -1);
156
157 // Copy text
158 SendMessageW(hText, WM_COPY, 0, 0);
159
160 // Restore previous values
161 SendMessageW(hText, EM_SETSEL, (WPARAM)dwStart, (LPARAM)dwEnd);
162
163 } else {
164
165 // Copy text
166 SendMessageW(hText, WM_COPY, 0, 0);
167 }
168 }
169
170 // Recover charset for the given font
171 static
172 BYTE
173 GetFontMetrics(HWND hWnd, HFONT hFont)
174 {
175 TEXTMETRIC tmFont;
176 HGDIOBJ hOldObj;
177 HDC hDC;
178
179 hDC = GetDC(hWnd);
180 hOldObj = SelectObject(hDC, hFont);
181 GetTextMetrics(hDC, &tmFont);
182 SelectObject(hDC, hOldObj);
183 ReleaseDC(hWnd, hDC);
184
185 return tmFont.tmCharSet;
186 }
187
188 // Select a new character
189 static
190 VOID
191 AddCharToSelection(HWND hDlg, WCHAR ch)
192 {
193 HWND hMap = GetDlgItem(hDlg, IDC_FONTMAP);
194 HWND hText = GetDlgItem(hDlg, IDC_TEXTBOX);
195 HFONT hFont;
196 LOGFONT lFont;
197 CHARFORMAT cf;
198
199 // Retrieve current character selected
200 if (ch == 0)
201 {
202 ch = (WCHAR) SendMessageW(hMap, FM_GETCHAR, 0, 0);
203 if (!ch)
204 return;
205 }
206
207 // Retrieve current selected font
208 hFont = (HFONT)SendMessage(hMap, FM_GETHFONT, 0, 0);
209
210 // Recover LOGFONT structure from hFont
211 if (!GetObject(hFont, sizeof(LOGFONT), &lFont))
212 return;
213
214 // Recover font properties of Richedit control
215 ZeroMemory(&cf, sizeof(cf));
216 cf.cbSize = sizeof(cf);
217 SendMessage(hText, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
218
219 // Apply properties of the new font
220 cf.bCharSet = GetFontMetrics(hText, hFont);
221
222 // Update font name
223 wcscpy(cf.szFaceName, lFont.lfFaceName);
224
225 // Update font properties
226 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
227
228 // Send selected character to Richedit
229 SendMessage(hText, WM_CHAR, (WPARAM)ch, 0);
230 }
231
232
233 static
234 void
235 UpdateSettings(HWND hDlg)
236 {
237 if (hDlg == hCharmapDlg)
238 {
239 Settings.IsAdvancedView =
240 SendDlgItemMessage(hDlg, IDC_CHECK_ADVANCED, BM_GETCHECK, 0, 0);
241 }
242
243 if (hDlg == hAdvancedDlg)
244 {
245 }
246 }
247
248 static
249 void
250 ChangeView(HWND hWnd)
251 {
252 RECT rcCharmap;
253 RECT rcAdvanced;
254 RECT rcPanelExt;
255 RECT rcPanelInt;
256 RECT rcStatus;
257 UINT DeX, DeY;
258 UINT xPos, yPos;
259 UINT Width, Height;
260 UINT DeskTopWidth, DeskTopHeight;
261
262 GetClientRect(hCharmapDlg, &rcCharmap);
263 GetClientRect(hAdvancedDlg, &rcAdvanced);
264 GetWindowRect(hWnd, &rcPanelExt);
265 GetClientRect(hWnd, &rcPanelInt);
266 GetClientRect(hStatusWnd, &rcStatus);
267
268 DeskTopWidth = GetSystemMetrics(SM_CXFULLSCREEN);
269 DeskTopHeight = GetSystemMetrics(SM_CYFULLSCREEN);
270
271 DeX = (rcPanelExt.right - rcPanelExt.left) - rcPanelInt.right;
272 DeY = (rcPanelExt.bottom - rcPanelExt.top) - rcPanelInt.bottom;
273
274 MoveWindow(hCharmapDlg, 0, 0, rcCharmap.right, rcCharmap.bottom, FALSE);
275 MoveWindow(hAdvancedDlg, 0, rcCharmap.bottom, rcAdvanced.right, rcAdvanced.bottom, FALSE);
276
277 ShowWindow(hAdvancedDlg, (Settings.IsAdvancedView) ? SW_SHOW : SW_HIDE);
278
279 xPos = rcPanelExt.left;
280 yPos = rcPanelExt.top;
281
282 Width = DeX + rcCharmap.right;
283 Height = DeY + rcCharmap.bottom + rcStatus.bottom;
284
285 if (Settings.IsAdvancedView)
286 Height += rcAdvanced.bottom;
287
288 if ((xPos + Width) > DeskTopWidth)
289 xPos += DeskTopWidth - (xPos + Width);
290
291 if ((yPos + Height) > DeskTopHeight)
292 yPos += DeskTopHeight - (yPos + Height);
293
294 MoveWindow(hWnd,
295 xPos, yPos,
296 Width, Height,
297 TRUE);
298 }
299
300 static
301 INT_PTR
302 CALLBACK
303 CharMapDlgProc(HWND hDlg,
304 UINT Message,
305 WPARAM wParam,
306 LPARAM lParam)
307 {
308 switch(Message)
309 {
310 case WM_INITDIALOG:
311 {
312 DWORD evMask;
313
314 FillFontStyleComboList(GetDlgItem(hDlg,
315 IDC_FONTCOMBO));
316
317 ChangeMapFont(hDlg);
318
319 // Configure Richedi control for sending notification changes.
320 evMask = SendDlgItemMessage(hDlg, IDC_TEXTBOX, EM_GETEVENTMASK, 0, 0);
321 evMask |= ENM_CHANGE;
322 SendDlgItemMessage(hDlg, IDC_TEXTBOX, EM_SETEVENTMASK, 0, (LPARAM)evMask);
323
324 return TRUE;
325 }
326
327 case WM_COMMAND:
328 {
329 switch(LOWORD(wParam))
330 {
331 case IDC_FONTMAP:
332 switch (HIWORD(wParam))
333 {
334 case FM_SETCHAR:
335 AddCharToSelection(hDlg, LOWORD(lParam));
336 break;
337 }
338 break;
339
340 case IDC_FONTCOMBO:
341 if (HIWORD(wParam) == CBN_SELCHANGE)
342 {
343 ChangeMapFont(hDlg);
344 }
345 break;
346
347 case IDC_SELECT:
348 AddCharToSelection(hDlg, 0);
349 break;
350
351 case IDC_TEXTBOX:
352 switch (HIWORD(wParam)) {
353 case EN_CHANGE:
354 if (GetWindowTextLength(GetDlgItem(hDlg, IDC_TEXTBOX)) == 0)
355 EnableWindow(GetDlgItem(hDlg, IDC_COPY), FALSE);
356 else
357 EnableWindow(GetDlgItem(hDlg, IDC_COPY), TRUE);
358 break;
359 }
360 break;
361
362 case IDC_COPY:
363 CopyCharacters(hDlg);
364 break;
365
366 case IDC_CHECK_ADVANCED:
367 UpdateSettings(hDlg);
368 ChangeView(GetParent(hDlg));
369 break;
370 }
371 }
372 break;
373
374 default:
375 break;
376 }
377
378 return FALSE;
379 }
380
381 static
382 INT_PTR
383 CALLBACK
384 AdvancedDlgProc(HWND hDlg,
385 UINT Message,
386 WPARAM wParam,
387 LPARAM lParam)
388 {
389 switch(Message)
390 {
391 case WM_INITDIALOG:
392 return TRUE;
393
394 default:
395 return FALSE;
396 }
397
398 return FALSE;
399 }
400
401 static int
402 OnCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
403 {
404 HMENU hSysMenu;
405 WCHAR lpAboutText[256];
406
407 hCharmapDlg = CreateDialog(hInstance,
408 MAKEINTRESOURCE(IDD_CHARMAP),
409 hWnd,
410 CharMapDlgProc);
411
412 hAdvancedDlg = CreateDialog(hInstance,
413 MAKEINTRESOURCE(IDD_ADVANCED),
414 hWnd,
415 AdvancedDlgProc);
416
417 hStatusWnd = CreateWindow(STATUSCLASSNAME,
418 NULL,
419 WS_CHILD | WS_VISIBLE,
420 0, 0, 0, 0,
421 hWnd,
422 (HMENU)IDD_STATUSBAR,
423 hInstance,
424 NULL);
425
426 // Set the status bar for multiple parts output
427 SendMessage(hStatusWnd, SB_SIMPLE, (WPARAM)FALSE, (LPARAM)0);
428
429 ChangeView(hWnd);
430
431 hSysMenu = GetSystemMenu(hWnd, FALSE);
432
433 if (hSysMenu != NULL)
434 {
435 if (LoadStringW(hInstance, IDS_ABOUT, lpAboutText, SIZEOF(lpAboutText)))
436 {
437 AppendMenuW(hSysMenu, MF_SEPARATOR, 0, NULL);
438 AppendMenuW(hSysMenu, MF_STRING, ID_ABOUT, lpAboutText);
439 }
440 }
441
442 return 0;
443 }
444
445 static LRESULT CALLBACK
446 PanelWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
447 {
448 switch (msg) {
449 case WM_CREATE:
450 return OnCreate(hWnd, wParam, lParam);
451
452 case WM_CLOSE:
453 DestroyWindow(hWnd);
454 return 0;
455
456 case WM_SIZE:
457 SendMessage(hStatusWnd, msg, wParam, lParam);
458 break;
459
460 case WM_DESTROY:
461 SaveSettings();
462 PostQuitMessage(0);
463 return 0;
464
465 case WM_SYSCOMMAND:
466 switch(wParam) {
467 case ID_ABOUT:
468 ShowAboutDlg(hWnd);
469 break;
470 }
471 break;
472
473 }
474
475 return DefWindowProc(hWnd, msg, wParam, lParam);
476 }
477
478 static HWND
479 InitInstance(HINSTANCE hInst)
480 {
481 WCHAR szClass[] = L"CharMap";
482 WCHAR szTitle[256];
483 WNDCLASSEXW wc;
484 HWND hWnd;
485
486 LoadStringW(hInst, IDS_TITLE, szTitle, SIZEOF(szTitle));
487
488 hSmIcon = LoadImage(hInstance,
489 MAKEINTRESOURCE(IDI_ICON),
490 IMAGE_ICON,
491 16,
492 16,
493 0);
494
495 hBgIcon = LoadImage(hInstance,
496 MAKEINTRESOURCE(IDI_ICON),
497 IMAGE_ICON,
498 32,
499 32,
500 0);
501
502 // Create workspace
503 ZeroMemory(&wc, sizeof(wc));
504
505 wc.cbSize = sizeof(wc);
506 wc.lpfnWndProc = PanelWndProc;
507 wc.hInstance = hInst;
508 wc.hIcon = hBgIcon;
509 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
510 wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
511 wc.lpszMenuName = NULL;
512 wc.lpszClassName = szClass;
513 wc.hIconSm = hSmIcon;
514
515 RegisterClassExW(&wc);
516
517 hWnd = CreateWindowW(
518 szClass,
519 szTitle,
520 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
521 CW_USEDEFAULT,
522 CW_USEDEFAULT,
523 CW_USEDEFAULT,
524 CW_USEDEFAULT,
525 NULL,
526 NULL,
527 hInst,
528 NULL);
529
530 if (hWnd != NULL)
531 {
532 LoadSettings();
533 ShowWindow(hWnd, SW_SHOW);
534 UpdateWindow(hWnd);
535 }
536
537 return hWnd;
538 }
539
540 INT
541 WINAPI
542 wWinMain(HINSTANCE hInst,
543 HINSTANCE hPrev,
544 LPWSTR Cmd,
545 int iCmd)
546 {
547 INITCOMMONCONTROLSEX iccx;
548 INT Ret = 1;
549 HMODULE hRichEd20;
550 MSG Msg;
551
552 hInstance = hInst;
553
554 iccx.dwSize = sizeof(INITCOMMONCONTROLSEX);
555 iccx.dwICC = ICC_TAB_CLASSES;
556 InitCommonControlsEx(&iccx);
557
558 if (RegisterMapClasses(hInstance))
559 {
560 hRichEd20 = LoadLibraryW(L"RICHED20.DLL");
561
562 if (hRichEd20 != NULL)
563 {
564 InitInstance(hInst);
565
566 for (;;)
567 {
568 if (GetMessage(&Msg, NULL, 0, 0) <= 0)
569 {
570 Ret = Msg.wParam;
571 break;
572 }
573
574 TranslateMessage(&Msg);
575 DispatchMessage(&Msg);
576 }
577
578 FreeLibrary(hRichEd20);
579 }
580 UnregisterMapClasses(hInstance);
581 }
582
583 return Ret;
584 }