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 return PanelOnCreate(hWnd, wParam, lParam); 494 495 case WM_CLOSE: 496 DestroyWindow(hWnd); 497 return 0; 498 499 case WM_SIZE: 500 SendMessage(hStatusWnd, msg, wParam, lParam); 501 break; 502 503 case WM_DESTROY: 504 SaveSettings(); 505 PostQuitMessage(0); 506 return 0; 507 508 case WM_SYSCOMMAND: 509 switch(wParam) { 510 case ID_ABOUT: 511 ShowAboutDlg(hWnd); 512 break; 513 } 514 break; 515 516 } 517 518 return DefWindowProc(hWnd, msg, wParam, lParam); 519 } 520 521 static HWND 522 InitInstance(HINSTANCE hInst) 523 { 524 WCHAR szClass[] = L"CharMap"; 525 WCHAR szTitle[256]; 526 WNDCLASSEXW wc; 527 HWND hWnd; 528 529 LoadStringW(hInst, IDS_TITLE, szTitle, SIZEOF(szTitle)); 530 531 hSmIcon = LoadImage(hInstance, 532 MAKEINTRESOURCE(IDI_ICON), 533 IMAGE_ICON, 534 16, 535 16, 536 0); 537 538 hBgIcon = LoadImage(hInstance, 539 MAKEINTRESOURCE(IDI_ICON), 540 IMAGE_ICON, 541 32, 542 32, 543 0); 544 545 // Create workspace 546 ZeroMemory(&wc, sizeof(wc)); 547 548 wc.cbSize = sizeof(wc); 549 wc.lpfnWndProc = PanelWndProc; 550 wc.hInstance = hInst; 551 wc.hIcon = hBgIcon; 552 wc.hCursor = LoadCursor(NULL, IDC_ARROW); 553 wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH); 554 wc.lpszMenuName = NULL; 555 wc.lpszClassName = szClass; 556 wc.hIconSm = hSmIcon; 557 558 RegisterClassExW(&wc); 559 560 hWnd = CreateWindowW( 561 szClass, 562 szTitle, 563 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, 564 CW_USEDEFAULT, 565 CW_USEDEFAULT, 566 CW_USEDEFAULT, 567 CW_USEDEFAULT, 568 NULL, 569 NULL, 570 hInst, 571 NULL); 572 573 if (hWnd != NULL) 574 { 575 LoadSettings(); 576 ShowWindow(hWnd, SW_SHOW); 577 UpdateWindow(hWnd); 578 } 579 580 return hWnd; 581 } 582 583 INT 584 WINAPI 585 wWinMain(HINSTANCE hInst, 586 HINSTANCE hPrev, 587 LPWSTR Cmd, 588 int iCmd) 589 { 590 INITCOMMONCONTROLSEX iccx; 591 INT Ret = 1; 592 HMODULE hRichEd20; 593 MSG Msg; 594 HINSTANCE hGetUName = NULL; 595 596 hInstance = hInst; 597 598 /* Mirroring code for the titlebar */ 599 switch (GetUserDefaultUILanguage()) 600 { 601 case MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT): 602 SetProcessDefaultLayout(LAYOUT_RTL); 603 break; 604 605 default: 606 break; 607 } 608 609 iccx.dwSize = sizeof(INITCOMMONCONTROLSEX); 610 iccx.dwICC = ICC_TAB_CLASSES; 611 InitCommonControlsEx(&iccx); 612 613 /* Loading the GetUName function */ 614 hGetUName = LoadLibraryW(L"getuname.dll"); 615 if (hGetUName != NULL) 616 { 617 GetUName = (GETUNAME) GetProcAddress(hGetUName, "GetUName"); 618 if (GetUName == NULL) 619 { 620 FreeLibrary(hGetUName); 621 hGetUName = NULL; 622 } 623 } 624 625 if (RegisterMapClasses(hInstance)) 626 { 627 hRichEd20 = LoadLibraryW(L"RICHED20.DLL"); 628 629 if (hRichEd20 != NULL) 630 { 631 InitInstance(hInst); 632 633 for (;;) 634 { 635 if (GetMessage(&Msg, NULL, 0, 0) <= 0) 636 { 637 Ret = Msg.wParam; 638 break; 639 } 640 641 TranslateMessage(&Msg); 642 DispatchMessage(&Msg); 643 } 644 645 FreeLibrary(hRichEd20); 646 } 647 UnregisterMapClasses(hInstance); 648 } 649 650 if (hGetUName != NULL) 651 FreeLibrary(hGetUName); 652 653 return Ret; 654 } 655