1 /* 2 * PROJECT: ReactOS Character Map 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: base/applications/charmap/map.c 5 * PURPOSE: class implementation for painting glyph region 6 * COPYRIGHT: Copyright 2007 Ged Murphy <gedmurphy@reactos.org> 7 * Copyright 2022 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 8 * 9 */ 10 11 #include "precomp.h" 12 13 #include <stdlib.h> 14 #include <winnls.h> 15 16 static const WCHAR szMapWndClass[] = L"FontMapWnd"; 17 static const WCHAR szLrgCellWndClass[] = L"LrgCellWnd"; 18 19 #define MAX_ROWS (0xFFFF / XCELLS) + 1 - YCELLS 20 21 static 22 VOID 23 SetGrid(PMAP infoPtr) 24 { 25 INT x, y; 26 PCELL Cell; 27 28 for (y = 0; y < YCELLS; y++) 29 for (x = 0; x < XCELLS; x++) 30 { 31 Cell = &infoPtr->Cells[y][x]; 32 Cell->CellExt.left = x * infoPtr->CellSize.cx + 1; 33 Cell->CellExt.top = y * infoPtr->CellSize.cy + 1; 34 Cell->CellExt.right = (x + 1) * infoPtr->CellSize.cx + 2; 35 Cell->CellExt.bottom = (y + 1) * infoPtr->CellSize.cy + 2; 36 37 Cell->CellInt = Cell->CellExt; 38 39 InflateRect(&Cell->CellInt, -1, -1); 40 } 41 } 42 43 static 44 VOID 45 UpdateCells(PMAP infoPtr) 46 { 47 INT x, y; 48 INT i = XCELLS * infoPtr->iYStart; 49 WCHAR ch; 50 PCELL Cell; 51 52 for (y = 0; y < YCELLS; ++y) 53 { 54 for (x = 0; x < XCELLS; ++x, ++i) 55 { 56 if (i < infoPtr->NumValidGlyphs) 57 ch = (WCHAR)infoPtr->ValidGlyphs[i]; 58 else 59 ch = 0xFFFF; 60 61 Cell = &infoPtr->Cells[y][x]; 62 Cell->ch = ch; 63 } 64 } 65 } 66 67 static 68 VOID 69 FillGrid(PMAP infoPtr, 70 PAINTSTRUCT *ps) 71 { 72 HFONT hOldFont; 73 INT x, y; 74 RECT rc; 75 PCELL Cell; 76 INT i; 77 HBRUSH hOldBrush, hbrGray = (HBRUSH)GetStockObject(LTGRAY_BRUSH); 78 HPEN hOldPen, hPenGray = CreatePen(PS_SOLID, 1, RGB(140, 140, 140)); 79 80 UpdateCells(infoPtr); 81 82 hOldFont = SelectObject(ps->hdc, infoPtr->hFont); 83 hOldPen = SelectObject(ps->hdc, GetStockObject(BLACK_PEN)); 84 hOldBrush = SelectObject(ps->hdc, GetStockObject(WHITE_BRUSH)); 85 86 i = XCELLS * infoPtr->iYStart; 87 88 for (y = 0; y < YCELLS; y++) 89 { 90 for (x = 0; x < XCELLS; x++, i++) 91 { 92 Cell = &infoPtr->Cells[y][x]; 93 if (!IntersectRect(&rc, &ps->rcPaint, &Cell->CellExt)) 94 continue; 95 96 rc = Cell->CellExt; 97 Rectangle(ps->hdc, rc.left, rc.top, rc.right, rc.bottom); 98 99 if (i < infoPtr->NumValidGlyphs) 100 { 101 DrawTextW(ps->hdc, &Cell->ch, 1, &Cell->CellInt, 102 DT_CENTER | DT_VCENTER | DT_SINGLELINE); 103 if (Cell == infoPtr->pActiveCell) 104 { 105 rc = Cell->CellInt; 106 107 /* Draw gray box */ 108 SelectObject(ps->hdc, GetStockObject(NULL_BRUSH)); 109 SelectObject(ps->hdc, hPenGray); 110 Rectangle(ps->hdc, rc.left, rc.top, rc.right, rc.bottom); 111 SelectObject(ps->hdc, hOldPen); 112 SelectObject(ps->hdc, hOldBrush); 113 114 if (GetFocus() == infoPtr->hMapWnd) 115 { 116 /* Draw focus rectangle */ 117 InflateRect(&rc, -1, -1); 118 DrawFocusRect(ps->hdc, &rc); 119 } 120 } 121 } 122 else 123 { 124 FillRect(ps->hdc, &Cell->CellInt, hbrGray); 125 } 126 } 127 } 128 129 SelectObject(ps->hdc, hOldFont); 130 SelectObject(ps->hdc, hOldPen); 131 SelectObject(ps->hdc, hOldBrush); 132 DeleteObject(hPenGray); 133 } 134 135 136 static 137 BOOL 138 CreateLargeCell(PMAP infoPtr) 139 { 140 RECT rLarge = infoPtr->pActiveCell->CellExt; 141 142 MapWindowPoints(infoPtr->hMapWnd, infoPtr->hParent, (LPPOINT)&rLarge, 2); 143 144 InflateRect(&rLarge, XLARGE - XCELLS, YLARGE - YCELLS); 145 146 infoPtr->hLrgWnd = CreateWindowExW(0, 147 szLrgCellWndClass, 148 NULL, 149 WS_CHILDWINDOW | WS_VISIBLE, 150 rLarge.left, 151 rLarge.top, 152 rLarge.right - rLarge.left, 153 rLarge.bottom - rLarge.top, 154 infoPtr->hParent, 155 NULL, 156 hInstance, 157 infoPtr); 158 if (!infoPtr->hLrgWnd) 159 return FALSE; 160 161 return TRUE; 162 } 163 164 165 static 166 VOID 167 MoveLargeCell(PMAP infoPtr) 168 { 169 RECT rLarge = infoPtr->pActiveCell->CellExt; 170 171 MapWindowPoints(infoPtr->hMapWnd, infoPtr->hParent, (LPPOINT)&rLarge, 2); 172 173 InflateRect(&rLarge, XLARGE - XCELLS, YLARGE - YCELLS); 174 175 MoveWindow(infoPtr->hLrgWnd, 176 rLarge.left, 177 rLarge.top, 178 rLarge.right - rLarge.left, 179 rLarge.bottom - rLarge.top, 180 TRUE); 181 182 InvalidateRect(infoPtr->hLrgWnd, NULL, TRUE); 183 } 184 185 186 static 187 VOID 188 GetPossibleCharacters(WCHAR* ch, INT chLen, INT codePageIdx) 189 { 190 INT i, j; 191 192 ZeroMemory(ch, sizeof(ch[0]) * chLen); 193 194 if (codePageIdx <= 0 || codePageIdx > SIZEOF(codePages)) 195 { 196 /* this is unicode, so just load up the first MAX_GLYPHS characters 197 start at 0x21 to bypass whitespace characters */ 198 INT len = min(MAX_GLYPHS, chLen); 199 for (i = 0x21, j = 0; i < len; i++) 200 ch[j++] = (WCHAR)i; 201 } 202 else 203 { 204 /* This is a codepage, so use NLS to translate the first 256 characters */ 205 CHAR multiByteString[256] = { 0 }; 206 for (i = 0x21; i < SIZEOF(multiByteString); i++) 207 multiByteString[i] = (CHAR)i; 208 209 if (!MultiByteToWideChar(codePages[codePageIdx - 1], 0, multiByteString, sizeof(multiByteString), ch, chLen)) 210 { 211 /* Failed for some reason, so clear the array */ 212 memset(ch, 0, sizeof(ch[0]) * chLen); 213 } 214 } 215 } 216 217 218 static 219 VOID 220 SetFont(PMAP infoPtr, 221 LPWSTR lpFontName) 222 { 223 HDC hdc; 224 WCHAR ch[MAX_GLYPHS]; 225 WORD out[MAX_GLYPHS]; 226 DWORD i, j; 227 228 /* Destroy Zoom window, since it was created with older font */ 229 DestroyWindow(infoPtr->hLrgWnd); 230 infoPtr->hLrgWnd = NULL; 231 232 if (infoPtr->hFont) 233 DeleteObject(infoPtr->hFont); 234 235 ZeroMemory(&infoPtr->CurrentFont, 236 sizeof(LOGFONTW)); 237 238 hdc = GetDC(infoPtr->hMapWnd); 239 infoPtr->CurrentFont.lfHeight = GetDeviceCaps(hdc, LOGPIXELSY) / 5; 240 241 infoPtr->CurrentFont.lfCharSet = DEFAULT_CHARSET; 242 lstrcpynW(infoPtr->CurrentFont.lfFaceName, 243 lpFontName, 244 SIZEOF(infoPtr->CurrentFont.lfFaceName)); 245 246 infoPtr->hFont = CreateFontIndirectW(&infoPtr->CurrentFont); 247 248 InvalidateRect(infoPtr->hMapWnd, 249 NULL, 250 TRUE); 251 252 // Get all the valid glyphs in this font 253 254 SelectObject(hdc, infoPtr->hFont); 255 256 // Get the code page associated with the selected 'character set' 257 GetPossibleCharacters(ch, MAX_GLYPHS, infoPtr->CharMap); 258 259 if (GetGlyphIndicesW(hdc, 260 ch, 261 MAX_GLYPHS, 262 out, 263 GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR) 264 { 265 j = 0; 266 for (i = 0; i < MAX_GLYPHS; i++) 267 { 268 if (out[i] != 0xffff && out[i] != 0x0000 && ch[i] != 0x0000) 269 { 270 infoPtr->ValidGlyphs[j] = ch[i]; 271 j++; 272 } 273 } 274 infoPtr->NumValidGlyphs = j; 275 } 276 277 ReleaseDC(infoPtr->hMapWnd, hdc); 278 279 infoPtr->NumRows = infoPtr->NumValidGlyphs / XCELLS; 280 if (infoPtr->NumValidGlyphs % XCELLS) 281 infoPtr->NumRows += 1; 282 infoPtr->NumRows = (infoPtr->NumRows > YCELLS) ? infoPtr->NumRows - YCELLS : 0; 283 284 SetScrollRange(infoPtr->hMapWnd, SB_VERT, 0, infoPtr->NumRows, FALSE); 285 SetScrollPos(infoPtr->hMapWnd, SB_VERT, 0, TRUE); 286 infoPtr->iYStart = 0; 287 } 288 289 290 static 291 LRESULT 292 NotifyParentOfSelection(PMAP infoPtr, 293 UINT code, 294 WCHAR ch) 295 { 296 LRESULT Ret = 0; 297 298 if (infoPtr->hParent != NULL) 299 { 300 DWORD dwIdc = GetWindowLongPtr(infoPtr->hMapWnd, GWLP_ID); 301 /* 302 * Push directly into the event queue instead of waiting 303 * the parent to be unlocked. 304 * High word of LPARAM is still available for future needs... 305 */ 306 Ret = PostMessage(infoPtr->hParent, 307 WM_COMMAND, 308 MAKELPARAM((WORD)dwIdc, (WORD)code), 309 (LPARAM)LOWORD(ch)); 310 } 311 312 return Ret; 313 } 314 315 316 static 317 VOID 318 LimitCaretXY(PMAP infoPtr, INT *pX, INT *pY) 319 { 320 INT i, X = *pX, Y = *pY, iYStart = infoPtr->iYStart; 321 322 i = XCELLS * (iYStart + Y) + X; 323 while (i >= infoPtr->NumValidGlyphs) 324 { 325 if (X > 0) 326 { 327 --X; 328 } 329 else 330 { 331 X = XCELLS - 1; 332 --Y; 333 } 334 i = XCELLS * (iYStart + Y) + X; 335 } 336 337 *pX = X; 338 *pY = Y; 339 } 340 341 static 342 VOID 343 SetCaretXY(PMAP infoPtr, INT X, INT Y, BOOL bLarge, BOOL bInvalidateAll) 344 { 345 346 /* set previous active cell to inactive */ 347 if (!bInvalidateAll) 348 { 349 InvalidateRect(infoPtr->hMapWnd, 350 &infoPtr->pActiveCell->CellInt, 351 FALSE); 352 } 353 354 LimitCaretXY(infoPtr, &X, &Y); 355 infoPtr->CaretX = X; 356 infoPtr->CaretY = Y; 357 UpdateCells(infoPtr); 358 359 /* set new cell to active */ 360 infoPtr->pActiveCell = &infoPtr->Cells[Y][X]; 361 if (!bInvalidateAll) 362 { 363 InvalidateRect(infoPtr->hMapWnd, 364 &infoPtr->pActiveCell->CellInt, 365 FALSE); 366 } 367 368 /* Create if needed */ 369 if (bLarge) 370 { 371 if (infoPtr->hLrgWnd) 372 MoveLargeCell(infoPtr); 373 else 374 CreateLargeCell(infoPtr); 375 } 376 else 377 { 378 /* Destroy large window */ 379 if (infoPtr->hLrgWnd) 380 { 381 DestroyWindow(infoPtr->hLrgWnd); 382 infoPtr->hLrgWnd = NULL; 383 } 384 } 385 386 if (bInvalidateAll) 387 InvalidateRect(infoPtr->hMapWnd, NULL, FALSE); 388 389 UpdateStatusBar(infoPtr->pActiveCell->ch); 390 } 391 392 static 393 VOID 394 OnClick(PMAP infoPtr, 395 WORD ptx, 396 WORD pty) 397 { 398 /* 399 * Find the cell the mouse pointer is over. 400 * Since each cell is the same size, this can be done quickly using CellSize. 401 * Clamp to XCELLS - 1 and YCELLS - 1 because the map can sometimes be slightly 402 * larger than infoPtr.CellSize * XCELLS , due to the map size being a non integer 403 * multiple of infoPtr.CellSize . 404 */ 405 INT x = min(XCELLS - 1, ptx / max(1, infoPtr->CellSize.cx)); 406 INT y = min(YCELLS - 1, pty / max(1, infoPtr->CellSize.cy)); 407 408 SetCaretXY(infoPtr, x, y, TRUE, FALSE); 409 } 410 411 412 static 413 BOOL 414 MapOnCreate(PMAP infoPtr, 415 HWND hwnd, 416 HWND hParent) 417 { 418 RECT rc; 419 420 infoPtr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MAP)); 421 if (!infoPtr) 422 return FALSE; 423 424 SetWindowLongPtrW(hwnd, 0, (LONG_PTR)infoPtr); 425 426 infoPtr->hMapWnd = hwnd; 427 infoPtr->hParent = hParent; 428 429 GetClientRect(hwnd, &rc); 430 infoPtr->ClientSize.cx = rc.right; 431 infoPtr->ClientSize.cy = rc.bottom; 432 infoPtr->CellSize.cx = infoPtr->ClientSize.cx / XCELLS; 433 infoPtr->CellSize.cy = infoPtr->ClientSize.cy / YCELLS; 434 435 infoPtr->pActiveCell = &infoPtr->Cells[0][0]; 436 437 SetGrid(infoPtr); 438 439 SetScrollPos(infoPtr->hParent, SB_VERT, 0, TRUE); 440 return TRUE; 441 } 442 443 static 444 VOID 445 OnVScroll(PMAP infoPtr, 446 INT Value, 447 INT Pos) 448 { 449 INT iYDiff, iOldYStart = infoPtr->iYStart; 450 INT X, Y; 451 452 switch (Value) 453 { 454 case SB_LINEUP: 455 infoPtr->iYStart -= 1; 456 break; 457 458 case SB_LINEDOWN: 459 infoPtr->iYStart += 1; 460 break; 461 462 case SB_PAGEUP: 463 infoPtr->iYStart -= YCELLS; 464 break; 465 466 case SB_PAGEDOWN: 467 infoPtr->iYStart += YCELLS; 468 break; 469 470 case SB_THUMBTRACK: 471 infoPtr->iYStart = Pos; 472 break; 473 474 case SB_TOP: 475 infoPtr->iYStart = 0; 476 SetCaretXY(infoPtr, 0, 0, FALSE, TRUE); 477 return; 478 479 case SB_BOTTOM: 480 infoPtr->iYStart = infoPtr->NumRows; 481 SetCaretXY(infoPtr, XCELLS - 1, YCELLS - 1, FALSE, TRUE); 482 break; 483 484 default: 485 break; 486 } 487 488 infoPtr->iYStart = max(0, infoPtr->iYStart); 489 infoPtr->iYStart = min(infoPtr->iYStart, infoPtr->NumRows); 490 491 UpdateCells(infoPtr); 492 493 X = infoPtr->CaretX; 494 Y = infoPtr->CaretY; 495 LimitCaretXY(infoPtr, &X, &Y); 496 SetCaretXY(infoPtr, X, Y, IsWindow(infoPtr->hLrgWnd), FALSE); 497 498 iYDiff = iOldYStart - infoPtr->iYStart; 499 if (iYDiff) 500 { 501 if (infoPtr->hLrgWnd != NULL) 502 { 503 ShowWindow(infoPtr->hLrgWnd, SW_HIDE); 504 } 505 506 SetScrollPos(infoPtr->hMapWnd, 507 SB_VERT, 508 infoPtr->iYStart, 509 TRUE); 510 511 if (abs(iYDiff) < YCELLS) 512 { 513 RECT rect; 514 515 /* Invalidate the rect around the active cell since a new cell will become active */ 516 if (infoPtr->pActiveCell) 517 { 518 InvalidateRect(infoPtr->hMapWnd, 519 &infoPtr->pActiveCell->CellExt, 520 TRUE); 521 } 522 523 GetClientRect(infoPtr->hMapWnd, &rect); 524 rect.top += 2; 525 rect.bottom -= 2; 526 ScrollWindowEx(infoPtr->hMapWnd, 527 0, 528 iYDiff * infoPtr->CellSize.cy, 529 &rect, 530 &rect, 531 NULL, 532 NULL, 533 SW_INVALIDATE); 534 } 535 else 536 { 537 InvalidateRect(infoPtr->hMapWnd, 538 NULL, 539 TRUE); 540 } 541 542 if (infoPtr->hLrgWnd != NULL) 543 { 544 ShowWindow(infoPtr->hLrgWnd, SW_SHOW); 545 } 546 } 547 548 UpdateStatusBar(infoPtr->pActiveCell->ch); 549 } 550 551 552 static 553 VOID 554 OnPaint(PMAP infoPtr, 555 WPARAM wParam) 556 { 557 PAINTSTRUCT ps; 558 HDC hdc; 559 560 if (wParam != 0) 561 { 562 if (!GetUpdateRect(infoPtr->hMapWnd, &ps.rcPaint, TRUE)) 563 return; 564 565 ps.hdc = (HDC)wParam; 566 } 567 else 568 { 569 hdc = BeginPaint(infoPtr->hMapWnd, &ps); 570 if (hdc == NULL) 571 return; 572 } 573 574 FillGrid(infoPtr, &ps); 575 576 if (wParam == 0) 577 { 578 EndPaint(infoPtr->hMapWnd, &ps); 579 } 580 } 581 582 static 583 VOID 584 MoveUpDown(PMAP infoPtr, INT DY) 585 { 586 INT Y = infoPtr->CaretY; 587 588 if (DY < 0) /* Move Up */ 589 { 590 if (Y <= 0) 591 { 592 SendMessageW(infoPtr->hMapWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), 0); 593 return; 594 } 595 596 Y -= 1; 597 } 598 else if (DY > 0) /* Move Down */ 599 { 600 if (Y + 1 >= YCELLS) 601 { 602 SendMessageW(infoPtr->hMapWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), 0); 603 return; 604 } 605 606 Y += 1; 607 } 608 609 SetCaretXY(infoPtr, infoPtr->CaretX, Y, IsWindow(infoPtr->hLrgWnd), FALSE); 610 } 611 612 static 613 VOID 614 MoveLeftRight(PMAP infoPtr, INT DX) 615 { 616 INT X = infoPtr->CaretX; 617 INT Y = infoPtr->CaretY; 618 619 if (DX < 0) /* Move Left */ 620 { 621 if (X <= 0) /* at left edge */ 622 { 623 if (Y <= 0) /* at top */ 624 { 625 Y = 0; 626 if (infoPtr->iYStart > 0) 627 X = XCELLS - 1; 628 SendMessageW(infoPtr->hMapWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), 0); 629 } 630 else 631 { 632 X = XCELLS - 1; 633 Y -= 1; 634 } 635 } 636 else /* Not at left edge */ 637 { 638 X -= 1; 639 } 640 } 641 else if (DX > 0) /* Move Right */ 642 { 643 if (X + 1 >= XCELLS) /* at right edge */ 644 { 645 if (Y + 1 >= YCELLS) /* at bottom */ 646 { 647 Y = YCELLS - 1; 648 if (infoPtr->iYStart < infoPtr->NumRows) 649 X = 0; 650 SendMessageW(infoPtr->hMapWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), 0); 651 } 652 else 653 { 654 X = 0; 655 Y += 1; 656 } 657 } 658 else 659 { 660 X += 1; 661 } 662 } 663 664 SetCaretXY(infoPtr, X, Y, IsWindow(infoPtr->hLrgWnd), FALSE); 665 } 666 667 static 668 VOID 669 OnKeyDown(PMAP infoPtr, WPARAM wParam, LPARAM lParam) 670 { 671 BOOL bCtrlDown = (GetKeyState(VK_CONTROL) < 0); 672 673 switch (wParam) 674 { 675 case VK_UP: 676 if (bCtrlDown) 677 SetCaretXY(infoPtr, infoPtr->CaretX, 0, FALSE, FALSE); 678 else 679 MoveUpDown(infoPtr, -1); 680 break; 681 682 case VK_DOWN: 683 if (bCtrlDown) 684 SetCaretXY(infoPtr, infoPtr->CaretX, YCELLS - 1, FALSE, FALSE); 685 else 686 MoveUpDown(infoPtr, +1); 687 break; 688 689 case VK_LEFT: 690 if (bCtrlDown) 691 SetCaretXY(infoPtr, 0, infoPtr->CaretY, FALSE, FALSE); 692 else 693 MoveLeftRight(infoPtr, -1); 694 break; 695 696 case VK_RIGHT: 697 if (bCtrlDown) 698 SetCaretXY(infoPtr, XCELLS - 1, infoPtr->CaretY, FALSE, FALSE); 699 else 700 MoveLeftRight(infoPtr, +1); 701 break; 702 703 case VK_PRIOR: /* Page Up */ 704 SendMessageW(infoPtr->hMapWnd, WM_VSCROLL, MAKEWPARAM(SB_PAGEUP, 0), 0); 705 break; 706 707 case VK_NEXT: /* Page Down */ 708 SendMessageW(infoPtr->hMapWnd, WM_VSCROLL, MAKEWPARAM(SB_PAGEDOWN, 0), 0); 709 break; 710 711 case VK_HOME: 712 if (bCtrlDown) 713 SendMessageW(infoPtr->hMapWnd, WM_VSCROLL, MAKEWPARAM(SB_TOP, 0), 0); 714 else 715 SetCaretXY(infoPtr, 0, infoPtr->CaretY, FALSE, FALSE); 716 break; 717 718 case VK_END: 719 if (bCtrlDown) 720 SendMessageW(infoPtr->hMapWnd, WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0); 721 else 722 SetCaretXY(infoPtr, XCELLS - 1, infoPtr->CaretY, FALSE, FALSE); 723 break; 724 } 725 } 726 727 LRESULT 728 CALLBACK 729 MapWndProc(HWND hwnd, 730 UINT uMsg, 731 WPARAM wParam, 732 LPARAM lParam) 733 { 734 PMAP infoPtr = (PMAP)GetWindowLongPtrW(hwnd, 0); 735 LRESULT Ret = 0; 736 WCHAR lfFaceName[LF_FACESIZE]; 737 738 switch (uMsg) 739 { 740 case WM_CREATE: 741 { 742 if (!MapOnCreate(infoPtr, 743 hwnd, 744 ((LPCREATESTRUCTW)lParam)->hwndParent)) 745 { 746 return (LRESULT)-1; 747 } 748 749 break; 750 } 751 752 case WM_KEYDOWN: 753 { 754 OnKeyDown(infoPtr, wParam, lParam); 755 break; 756 } 757 758 case WM_LBUTTONDOWN: 759 { 760 SetFocus(hwnd); 761 OnClick(infoPtr, LOWORD(lParam), HIWORD(lParam)); 762 break; 763 } 764 765 case WM_MOUSEMOVE: 766 { 767 if (wParam & MK_LBUTTON) 768 { 769 OnClick(infoPtr, LOWORD(lParam), HIWORD(lParam)); 770 } 771 break; 772 } 773 774 case WM_LBUTTONDBLCLK: 775 { 776 if (!infoPtr->pActiveCell || GetFocus() != hwnd) 777 break; 778 779 NotifyParentOfSelection(infoPtr, 780 FM_SETCHAR, 781 infoPtr->pActiveCell->ch); 782 783 if (infoPtr->hLrgWnd) 784 { 785 DestroyWindow(infoPtr->hLrgWnd); 786 infoPtr->hLrgWnd = NULL; 787 } 788 break; 789 } 790 791 case WM_VSCROLL: 792 { 793 OnVScroll(infoPtr, LOWORD(wParam), HIWORD(wParam)); 794 break; 795 } 796 797 case FM_SETCHARMAP: 798 infoPtr->CaretX = infoPtr->CaretY = infoPtr->iYStart = 0; 799 infoPtr->CharMap = LOWORD(wParam); 800 wcsncpy(lfFaceName, 801 infoPtr->CurrentFont.lfFaceName, 802 SIZEOF(lfFaceName)); 803 SetFont(infoPtr, lfFaceName); 804 break; 805 806 case FM_SETFONT: 807 infoPtr->CaretX = infoPtr->CaretY = infoPtr->iYStart = 0; 808 SetFont(infoPtr, (LPWSTR)lParam); 809 break; 810 811 case FM_GETCHAR: 812 { 813 if (!infoPtr->pActiveCell) return 0; 814 return infoPtr->pActiveCell->ch; 815 } 816 817 case FM_GETHFONT: 818 return (LRESULT)infoPtr->hFont; 819 820 case WM_PAINT: 821 OnPaint(infoPtr, wParam); 822 break; 823 824 case WM_DESTROY: 825 DeleteObject(infoPtr->hFont); 826 HeapFree(GetProcessHeap(), 0, infoPtr); 827 SetWindowLongPtrW(hwnd, 0, (LONG_PTR)NULL); 828 break; 829 830 case WM_GETDLGCODE: 831 return DLGC_WANTARROWS; 832 833 case WM_SETFOCUS: 834 case WM_KILLFOCUS: 835 if (!infoPtr->hLrgWnd) 836 InvalidateRect(hwnd, &(infoPtr->pActiveCell->CellInt), FALSE); 837 break; 838 839 default: 840 Ret = DefWindowProcW(hwnd, uMsg, wParam, lParam); 841 break; 842 } 843 844 return Ret; 845 } 846 847 848 BOOL 849 RegisterMapClasses(HINSTANCE hInstance) 850 { 851 WNDCLASSW wc = {0}; 852 853 wc.style = CS_DBLCLKS; 854 wc.lpfnWndProc = MapWndProc; 855 wc.cbWndExtra = sizeof(PMAP); 856 wc.hInstance = hInstance; 857 wc.hCursor = LoadCursorW(NULL, 858 (LPWSTR)IDC_ARROW); 859 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 860 wc.lpszClassName = szMapWndClass; 861 862 if (RegisterClassW(&wc)) 863 { 864 wc.lpfnWndProc = LrgCellWndProc; 865 wc.cbWndExtra = 0; 866 wc.lpszClassName = szLrgCellWndClass; 867 868 return RegisterClassW(&wc) != 0; 869 } 870 871 return FALSE; 872 } 873 874 VOID 875 UnregisterMapClasses(HINSTANCE hInstance) 876 { 877 UnregisterClassW(szMapWndClass, hInstance); 878 UnregisterClassW(szLrgCellWndClass, hInstance); 879 } 880