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