1 /* 2 * PROJECT: ReactOS Character Map 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: base/applications/charmap/MainWindow.cpp 5 * PURPOSE: Implements the main dialog window 6 * COPYRIGHT: Copyright 2015 Ged Murphy <gedmurphy@reactos.org> 7 */ 8 9 10 #include "precomp.h" 11 #include "MainWindow.h" 12 13 14 /* DATA *****************************************************/ 15 16 #define ID_ABOUT 0x1 17 18 HINSTANCE g_hInstance = NULL; 19 20 21 /* PUBLIC METHODS **********************************************/ 22 23 CCharMapWindow::CCharMapWindow(void) : 24 m_hMainWnd(NULL), 25 m_hStatusBar(NULL), 26 m_CmdShow(0), 27 m_hRichEd(NULL), 28 m_GridView(nullptr) 29 { 30 m_GridView = new CGridView(); 31 } 32 33 CCharMapWindow::~CCharMapWindow(void) 34 { 35 } 36 37 bool 38 CCharMapWindow::Create(_In_ HINSTANCE hInst, 39 _In_ int nCmdShow) 40 { 41 INITCOMMONCONTROLSEX icex; 42 CAtlStringW szAppName; 43 int Ret = 1; 44 45 // Store the instance 46 g_hInstance = hInst; 47 m_CmdShow = nCmdShow; 48 49 // Initialize common controls 50 icex.dwSize = sizeof(INITCOMMONCONTROLSEX); 51 icex.dwICC = ICC_BAR_CLASSES | ICC_COOL_CLASSES; 52 InitCommonControlsEx(&icex); 53 54 // Load the application name 55 if (szAppName.LoadStringW(g_hInstance, IDS_TITLE)) 56 { 57 // Initialize the main window 58 if (Initialize(szAppName, nCmdShow)) 59 { 60 // Run the application 61 Ret = Run(); 62 63 // Uninitialize the main window 64 Uninitialize(); 65 } 66 } 67 68 return (Ret == 0); 69 } 70 71 72 73 /* PRIVATE METHODS **********************************************/ 74 75 bool 76 CCharMapWindow::Initialize(_In_z_ LPCTSTR lpCaption, 77 _In_ int nCmdShow) 78 { 79 // The dialog has a rich edit text box 80 m_hRichEd = LoadLibraryW(L"riched20.DLL"); 81 if (m_hRichEd == NULL) return false; 82 83 return !!(CreateDialogParamW(g_hInstance, 84 MAKEINTRESOURCE(IDD_CHARMAP), 85 NULL, 86 DialogProc, 87 (LPARAM)this)); 88 } 89 90 void 91 CCharMapWindow::Uninitialize(void) 92 { 93 if (m_hRichEd) 94 FreeLibrary(m_hRichEd); 95 } 96 97 int 98 CCharMapWindow::Run(void) 99 { 100 MSG Msg; 101 102 // Pump the message queue 103 while (GetMessageW(&Msg, NULL, 0, 0) != 0) 104 { 105 TranslateMessage(&Msg); 106 DispatchMessageW(&Msg); 107 } 108 109 return 0; 110 } 111 112 void 113 CCharMapWindow::UpdateStatusBar(_In_ bool InMenuLoop) 114 { 115 SendMessageW(m_hStatusBar, 116 SB_SIMPLE, 117 (WPARAM)InMenuLoop, 118 0); 119 } 120 121 bool 122 CCharMapWindow::CreateStatusBar(void) 123 { 124 int StatWidths[] = { 110, -1 }; // widths of status bar 125 bool bRet = FALSE; 126 127 // Create the status bar 128 m_hStatusBar = CreateWindowExW(0, 129 STATUSCLASSNAME, 130 NULL, 131 WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, 132 0, 0, 0, 0, 133 m_hMainWnd, 134 (HMENU)IDD_STATUSBAR, 135 g_hInstance, 136 NULL); 137 if (m_hStatusBar) 138 { 139 // Create the sections 140 bRet = (SendMessageW(m_hStatusBar, 141 SB_SETPARTS, 142 sizeof(StatWidths) / sizeof(int), 143 (LPARAM)StatWidths) != 0); 144 145 // Set the status bar for multiple parts output 146 SendMessage(m_hStatusBar, SB_SIMPLE, (WPARAM)FALSE, (LPARAM)0); 147 } 148 149 return bRet; 150 } 151 152 bool 153 CCharMapWindow::StatusBarLoadString(_In_ HWND hStatusBar, 154 _In_ INT PartId, 155 _In_ HINSTANCE hInstance, 156 _In_ UINT uID) 157 { 158 CAtlStringW szMessage; 159 bool bRet = false; 160 161 // Load the string from the resource 162 if (szMessage.LoadStringW(hInstance, uID)) 163 { 164 // Display it on the status bar 165 bRet = (SendMessageW(hStatusBar, 166 SB_SETTEXT, 167 (WPARAM)PartId, 168 (LPARAM)szMessage.GetBuffer()) != 0); 169 } 170 171 return bRet; 172 } 173 174 BOOL 175 CCharMapWindow::OnCreate(_In_ HWND hDlg) 176 { 177 m_hMainWnd = hDlg; 178 179 if (!CreateStatusBar()) 180 return FALSE; 181 182 if (!m_GridView->Create(hDlg)) 183 return FALSE; 184 185 // Load an 'about' option into the system menu 186 HMENU hSysMenu; 187 hSysMenu = GetSystemMenu(m_hMainWnd, FALSE); 188 if (hSysMenu != NULL) 189 { 190 CAtlStringW AboutText; 191 if (AboutText.LoadStringW(IDS_ABOUT)) 192 { 193 AppendMenuW(hSysMenu, MF_SEPARATOR, 0, NULL); 194 AppendMenuW(hSysMenu, MF_STRING, ID_ABOUT, AboutText); 195 } 196 } 197 198 // Add all the fonts to the list 199 if (!CreateFontComboBox()) 200 return FALSE; 201 202 ChangeMapFont(); 203 204 // Configure Richedit control for sending notification changes. 205 DWORD evMask; 206 evMask = SendDlgItemMessage(hDlg, IDC_TEXTBOX, EM_GETEVENTMASK, 0, 0); 207 evMask |= ENM_CHANGE; 208 SendDlgItemMessage(hDlg, IDC_TEXTBOX, EM_SETEVENTMASK, 0, (LPARAM)evMask); 209 210 // Display the window according to the user request 211 ShowWindow(m_hMainWnd, m_CmdShow); 212 213 return TRUE; 214 } 215 216 BOOL 217 CCharMapWindow::OnSize( 218 _In_ WPARAM wParam 219 ) 220 { 221 RECT rcClient, rcStatus; 222 INT lvHeight, iStatusHeight; 223 224 // Resize the status bar 225 SendMessage(m_hStatusBar, WM_SIZE, 0, 0); 226 227 // Get the statusbar rect and save the height 228 GetWindowRect(m_hStatusBar, &rcStatus); 229 iStatusHeight = rcStatus.bottom - rcStatus.top; 230 231 // Get the full client rect 232 GetClientRect(m_hMainWnd, &rcClient); 233 234 // Calculate the remaining height for the gridview 235 lvHeight = rcClient.bottom - iStatusHeight; 236 237 // Resize the grid view 238 SendMessageW(m_GridView->GetHwnd(), WM_SIZE, wParam, 0); 239 240 return TRUE; 241 } 242 243 BOOL 244 CCharMapWindow::OnNotify(_In_ LPARAM lParam) 245 { 246 LPNMHDR NmHdr = (LPNMHDR)lParam; 247 LRESULT Ret = 0; 248 249 switch (NmHdr->code) 250 { 251 case NM_RCLICK: 252 { 253 break; 254 } 255 256 case NM_DBLCLK: 257 case NM_RETURN: 258 { 259 break; 260 } 261 } 262 263 return Ret; 264 } 265 266 BOOL 267 CCharMapWindow::OnContext(_In_ LPARAM lParam) 268 { 269 return 0;// m_GridView->OnContextMenu(lParam); 270 } 271 272 BOOL 273 CCharMapWindow::OnCommand(_In_ WPARAM wParam, 274 _In_ LPARAM /*lParam*/) 275 { 276 LRESULT RetCode = 0; 277 WORD Msg; 278 279 // Get the message 280 Msg = LOWORD(wParam); 281 282 switch (Msg) 283 { 284 case IDC_CHECK_ADVANCED: 285 break; 286 287 case IDC_FONTCOMBO: 288 if (HIWORD(wParam) == CBN_SELCHANGE) 289 { 290 ChangeMapFont(); 291 } 292 break; 293 294 default: 295 // We didn't handle it 296 RetCode = -1; 297 break; 298 } 299 300 return RetCode; 301 } 302 303 BOOL 304 CCharMapWindow::OnDestroy(void) 305 { 306 // Clear the user data pointer 307 SetWindowLongPtr(m_hMainWnd, GWLP_USERDATA, 0); 308 309 // Break the message loop 310 PostQuitMessage(0); 311 312 return TRUE; 313 } 314 315 INT_PTR CALLBACK 316 CCharMapWindow::DialogProc( 317 _In_ HWND hwndDlg, 318 _In_ UINT Msg, 319 _In_ WPARAM wParam, 320 _In_ LPARAM lParam 321 ) 322 { 323 CCharMapWindow *This; 324 LRESULT RetCode = 0; 325 326 // Get the object pointer from window context 327 This = (CCharMapWindow *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 328 if (This == NULL) 329 { 330 // Check that this isn't a create message 331 if (Msg != WM_INITDIALOG) 332 { 333 // Don't handle null info pointer 334 return FALSE; 335 } 336 } 337 338 switch (Msg) 339 { 340 case WM_INITDIALOG: 341 { 342 // Get the object pointer from the create param 343 This = (CCharMapWindow *)lParam; 344 345 // Store the pointer in the window's global user data 346 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)This); 347 348 // Call the create handler 349 return This->OnCreate(hwndDlg); 350 } 351 352 case WM_SIZE: 353 { 354 return This->OnSize(wParam); 355 } 356 357 case WM_NOTIFY: 358 { 359 return This->OnNotify(lParam); 360 } 361 362 case WM_CONTEXTMENU: 363 { 364 return This->OnContext(lParam); 365 } 366 367 case WM_COMMAND: 368 { 369 return This->OnCommand(wParam, lParam); 370 } 371 372 case WM_SYSCOMMAND: 373 switch (wParam) 374 { 375 case ID_ABOUT: 376 MessageBoxW(This->m_hMainWnd, 377 L"ReactOS Character Map\nCopyright Ged Murphy 2015", 378 L"About", 379 MB_OK | MB_APPLMODAL); 380 break; 381 } 382 break; 383 384 case WM_ENTERMENULOOP: 385 { 386 This->UpdateStatusBar(true); 387 return TRUE; 388 } 389 390 case WM_EXITMENULOOP: 391 { 392 This->UpdateStatusBar(false); 393 return TRUE; 394 } 395 396 case WM_CLOSE: 397 { 398 // Destroy the main window 399 return DestroyWindow(hwndDlg); 400 } 401 402 403 case WM_DESTROY: 404 { 405 // Call the destroy handler 406 return This->OnDestroy(); 407 } 408 } 409 410 return FALSE; 411 } 412 413 struct EnumFontParams 414 { 415 CCharMapWindow *This; 416 HWND hCombo; 417 }; 418 419 int 420 CALLBACK 421 CCharMapWindow::EnumDisplayFont(ENUMLOGFONTEXW *lpelfe, 422 NEWTEXTMETRICEXW *lpntme, 423 DWORD FontType, 424 LPARAM lParam) 425 { 426 EnumFontParams *Params = (EnumFontParams *)lParam; 427 LPWSTR pszName = lpelfe->elfLogFont.lfFaceName; 428 429 /* Skip rotated font */ 430 if (pszName[0] == L'@') return 1; 431 432 /* make sure font doesn't already exist in our list */ 433 if (SendMessageW(Params->hCombo, 434 CB_FINDSTRINGEXACT, 435 0, 436 (LPARAM)pszName) == CB_ERR) 437 { 438 INT idx; 439 idx = (INT)SendMessageW(Params->hCombo, 440 CB_ADDSTRING, 441 0, 442 (LPARAM)pszName); 443 444 /* record the font's attributes (Fixedwidth and Truetype) */ 445 BOOL fFixed = (lpelfe->elfLogFont.lfPitchAndFamily & FIXED_PITCH) ? TRUE : FALSE; 446 BOOL fTrueType = (lpelfe->elfLogFont.lfOutPrecision == OUT_STROKE_PRECIS) ? TRUE : FALSE; 447 448 /* store this information in the list-item's userdata area */ 449 SendMessageW(Params->hCombo, 450 CB_SETITEMDATA, 451 idx, 452 MAKEWPARAM(fFixed, fTrueType)); 453 } 454 455 return 1; 456 } 457 458 459 bool 460 CCharMapWindow::CreateFontComboBox() 461 { 462 HWND hCombo; 463 hCombo = GetDlgItem(m_hMainWnd, IDC_FONTCOMBO); 464 465 NONCLIENTMETRICSW NonClientMetrics; 466 NonClientMetrics.cbSize = sizeof(NONCLIENTMETRICSW); 467 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 468 sizeof(NONCLIENTMETRICSW), 469 &NonClientMetrics, 470 0); 471 472 // Get a handle to the font 473 HFONT GuiFont; 474 GuiFont = CreateFontIndirectW(&NonClientMetrics.lfMessageFont); 475 476 // Set the font used in the combo box 477 SendMessageW(hCombo, 478 WM_SETFONT, 479 (WPARAM)GuiFont, 480 0); 481 482 // Set the fonts which we want to enumerate 483 LOGFONTW FontsToEnum; 484 ZeroMemory(&FontsToEnum, sizeof(LOGFONTW)); 485 FontsToEnum.lfCharSet = DEFAULT_CHARSET; 486 487 // Set the params we want to pass to the callback 488 EnumFontParams Params; 489 Params.This = this; 490 Params.hCombo = hCombo; 491 492 // Get a DC for combo box 493 HDC hdc; 494 hdc = GetDC(hCombo); 495 496 // Enumerate all the fonts 497 int ret; 498 ret = EnumFontFamiliesExW(hdc, 499 &FontsToEnum, 500 (FONTENUMPROCW)EnumDisplayFont, 501 (LPARAM)&Params, 502 0); 503 504 ReleaseDC(hCombo, hdc); 505 DeleteObject(GuiFont); 506 507 // Select the first item in the list 508 SendMessageW(hCombo, 509 CB_SETCURSEL, 510 0, 511 0); 512 513 return (ret == 1); 514 } 515 516 bool 517 CCharMapWindow::ChangeMapFont( 518 ) 519 { 520 HWND hCombo; 521 hCombo = GetDlgItem(m_hMainWnd, IDC_FONTCOMBO); 522 523 INT Length; 524 Length = GetWindowTextLengthW(hCombo); 525 if (!Length) return false; 526 527 CAtlStringW FontName; 528 FontName.Preallocate(Length); 529 530 SendMessageW(hCombo, 531 WM_GETTEXT, 532 FontName.GetAllocLength(), 533 (LPARAM)FontName.GetBuffer()); 534 535 return m_GridView->SetFont(FontName); 536 } 537