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