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