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