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