|
|
1.1 ! root 1: ! 2: /******************************************************************************\ ! 3: * This is a part of the Microsoft Source Code Samples. ! 4: * Copyright (C) 1993 Microsoft Corporation. ! 5: * All rights reserved. ! 6: * This source code is only intended as a supplement to ! 7: * Microsoft Development Tools and/or WinHelp documentation. ! 8: * See these sources for detailed information regarding the ! 9: * Microsoft samples programs. ! 10: \******************************************************************************/ ! 11: ! 12: /**************************************************************************\ ! 13: * display.c -- module to support the main MDI child windows. ! 14: * ! 15: * This module contains Window Procedure, openDisplay() and closeDisplay() ! 16: * routines. Call openDisplay() one time per process before creating the ! 17: * first window, and call closeDisplay() one time at process termination. ! 18: * ! 19: * windows are created in main frame window procedure. ! 20: * ! 21: * design: We have one window procedure here for potentially multiple ! 22: * MDI child windows. The nCharPerLine, SqrHeight, and SqrWidth are ! 23: * stored on a per window basis. Also, the window class is registered ! 24: * with the style CS_OWNDC. For this reason, it is possible to select ! 25: * a logical font into the HDC, and it will be there each time you get ! 26: * the DC new for the window. In this way we have a log font for each ! 27: * window without actually doing any work in this module. ! 28: * ! 29: * Some of the data is global, and works for all of the windows. The ! 30: * startcount & endcount arrays are a good example. These are computed ! 31: * once when the font is created, but the values remain the same for each ! 32: * window. Thus we have the following assumption: ! 33: * ! 34: * 1. No fonts will be installed or removed while program is running. ! 35: * (CountUCSegments values remain valid for run time duration). ! 36: * ! 37: * ! 38: * There are WM_USER+ messages to set values for this window, and to ! 39: * notify it of global changes. Looking at the create time, user message ! 40: * stream is helpful. On the WM_CREATE message, we send ourselves a ! 41: * WMU_NEWFONT message to create a logical font and count the number of ! 42: * character ranges (segments). Before returning from this message, we ! 43: * send ourselves a WMU_NEWRANGE message to set the title, and the ! 44: * horizontal scroll bar correctly. ! 45: * ! 46: * ! 47: \**************************************************************************/ ! 48: #define UNICODE ! 49: ! 50: #include <windows.h> ! 51: #include "uniput.h" ! 52: #include "display.h" ! 53: ! 54: ! 55: /* global variables store the start and end codepoints for UC ranges. */ ! 56: #define MAXSEGMENTS 100 ! 57: USHORT *endCount= NULL; ! 58: USHORT *startCount= NULL; ! 59: ! 60: int CountUCSegments (HDC); ! 61: /* error return value from CountUCSegments */ ! 62: #define SEGMENTERROR -1 ! 63: ! 64: ! 65: /* conversion between (x,y) pairs and rectangle index */ ! 66: int transXYtoIndex (int, int, int, int, int); ! 67: int transIndextoRect (int, PRECT, int, int, int); ! 68: ! 69: ! 70: /* window extra bytes for use to store window specific data (see register class) */ ! 71: #define GWLU_NCHAR 0 ! 72: #define GWLU_SQRHEIGHT 4 ! 73: #define GWLU_SQRWIDTH 8 ! 74: ! 75: ! 76: ! 77: ! 78: ! 79: /* Global logfont. Used for CreateFontIndirect(). ! 80: * also regerenced in the uniput.c file. ! 81: */ ! 82: LOGFONT logfont = { ! 83: UCFONTHEIGHT , ! 84: UCFONTWIDTH , ! 85: 0 , ! 86: 0 , ! 87: 400 , ! 88: 0 , ! 89: 0 , ! 90: 0 , ! 91: UNICODE_CHARSET , ! 92: 0 , ! 93: 0 , ! 94: 2 , ! 95: 2 , ! 96: TEXT("Lucida Sans Unicode")}; ! 97: ! 98: ! 99: /* Global, class specific data. ! 100: * ought to allocate once per class, and free once at app exit time. ! 101: */ ! 102: HDC hdcMemXOR; ! 103: HBITMAP hbmMemXOR; ! 104: PVOID pbitsXOR, pbitsAND; ! 105: ! 106: int FontWidth, FontHeight; ! 107: int nSegments; ! 108: ! 109: /**************************************************************************\ ! 110: * ! 111: * function: openDisplay() ! 112: * ! 113: * Global variables: ! 114: * HDC hdcMemXOR; ! 115: * HBITMAP hbmMemXOR; ! 116: * PVOID pbitsXOR, pbitsAND; ! 117: * int FontWidth, FontHeight; ! 118: * int nSegments; ! 119: * ! 120: * returns: TRUE - if success, FALSE - if fail. ! 121: * ! 122: * essential side effect: ! 123: * Registers window class, and initial global variables. ! 124: \**************************************************************************/ ! 125: int openDisplay(VOID ) ! 126: { ! 127: WNDCLASS wc; ! 128: static int cxCursor, cyCursor; ! 129: HFONT hfont; ! 130: ! 131: /* Register the window class*/ ! 132: wc.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC; ! 133: wc.lpfnWndProc = (WNDPROC)DisplayWndProc; ! 134: wc.cbClsExtra = 0; ! 135: wc.cbWndExtra = 12; ! 136: wc.hInstance = hInst; ! 137: wc.hIcon = LoadIcon(hInst, TEXT("uniputIcon")); ! 138: wc.hCursor = LoadCursor(NULL, IDC_ARROW); ! 139: wc.hbrBackground = GetStockObject (WHITE_BRUSH); ! 140: wc.lpszMenuName = NULL; ! 141: wc.lpszClassName = DISPLAYCLASS; ! 142: ! 143: if (!RegisterClass(&wc)) return (FALSE); ! 144: ! 145: cxCursor = GetSystemMetrics (SM_CXCURSOR); ! 146: cyCursor = GetSystemMetrics (SM_CYCURSOR); ! 147: ! 148: /* get pointer to 0-init memory */ ! 149: pbitsAND = (PVOID) LocalAlloc (LPTR, cxCursor*cyCursor/8); ! 150: ! 151: /* Create a memory DC to draw into for creating cursors. */ ! 152: hdcMemXOR = CreateCompatibleDC (NULL); ! 153: hbmMemXOR = CreateBitmap (cxCursor,cyCursor,1,4,NULL); ! 154: SelectObject (hdcMemXOR, hbmMemXOR); ! 155: ! 156: /* set text modes for the memory HDC */ ! 157: SetBkMode (hdcMemXOR, TRANSPARENT); ! 158: SetTextAlign (hdcMemXOR, TA_CENTER | TA_TOP); ! 159: ! 160: /* set a unicode font into the memory DC */ ! 161: logfont.lfHeight = cyCursor *2/3; // HACK.. scale down Y ! 162: logfont.lfWidth = cxCursor *2/3; ! 163: hfont = CreateFontIndirect (&logfont); ! 164: SelectObject (hdcMemXOR, hfont); ! 165: ! 166: /* get pointer to be used later as pointer to bitmap bits */ ! 167: pbitsXOR = (PVOID) LocalAlloc (LPTR, cxCursor*cyCursor/2); ! 168: ! 169: /* Assume that we got a unicode font. ! 170: * Count the number of segments, and fill in the proper global ! 171: * variables specifying the code point ranges covered. ! 172: */ ! 173: nSegments = CountUCSegments (hdcMemXOR); /* slow computation */ ! 174: ! 175: ! 176: /* verify that we have SOME ranges to work with */ ! 177: if (nSegments == SEGMENTERROR) return FALSE; ! 178: ! 179: /* warn the user if we can't find the right font */ ! 180: if (nSegments < 30) ! 181: MessageBox (NULL, ! 182: TEXT("Working with limited codepoint coverage. \n Install uclucida.ttf"), ! 183: TEXT("Warning: Lucida Sans Unicode font not found."), MB_OK); ! 184: ! 185: ! 186: ! 187: FontWidth = UCFONTWIDTH; ! 188: FontHeight = UCFONTHEIGHT; ! 189: ! 190: return TRUE; ! 191: } ! 192: ! 193: /**************************************************************************\ ! 194: * ! 195: * function: closeDisplay() ! 196: * ! 197: * Global variables: ! 198: * HDC hdcMemXOR; ! 199: * HBITMAP hbmMemXOR; ! 200: * PVOID pbitsXOR, pbitsAND; ! 201: * ! 202: * essential side effect: ! 203: * Frees global variables. ! 204: \**************************************************************************/ ! 205: int closeDisplay(VOID) ! 206: { ! 207: HFONT hfont; ! 208: ! 209: hfont = SelectObject (hdcMemXOR, GetStockObject(SYSTEM_FONT)); ! 210: DeleteObject (hfont); ! 211: DeleteDC (hdcMemXOR); ! 212: DeleteObject (hbmMemXOR); ! 213: ! 214: LocalFree (LocalHandle (pbitsXOR)); ! 215: LocalFree (LocalHandle (pbitsAND)); ! 216: return TRUE; ! 217: } ! 218: ! 219: ! 220: /**************************************************************************\ ! 221: * ! 222: * function: DisplayWndProc() ! 223: * ! 224: * input parameters: normal window procedure parameters. ! 225: * ! 226: \**************************************************************************/ ! 227: LRESULT CALLBACK DisplayWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) ! 228: { ! 229: static HFONT hfont, hfontOld; ! 230: ! 231: static HDC hdc; ! 232: static RECT rect; ! 233: static int iSeg; ! 234: static TCHAR buffer[100]; ! 235: ! 236: /* rDown and index used as the user points to a square. */ ! 237: static RECT rDown; ! 238: static int index; ! 239: ! 240: static WCHAR DragDropChar; ! 241: static HICON hIcon; ! 242: ! 243: ! 244: ! 245: switch (message) { ! 246: ! 247: /**********************************************************************\ ! 248: * WM_CREATE ! 249: * ! 250: * Set up the LOGFONT in the HDC for this window. ! 251: \**********************************************************************/ ! 252: case WM_CREATE: ! 253: SendMessage (hwnd, WMU_SETNCHAR, 16, 0); ! 254: SendMessage (hwnd, WMU_NEWFONT, FontWidth, FontHeight); ! 255: break; ! 256: ! 257: ! 258: /**********************************************************************\ ! 259: * WM_DESTROY ! 260: * ! 261: * Get rid of the logical font we create for each display window. ! 262: * relying here on CS_ONWDC ! 263: \**********************************************************************/ ! 264: case WM_DESTROY: ! 265: hdc = GetDC (hwnd); ! 266: hfont = SelectObject (hdc, GetStockObject(SYSTEM_FONT)); ! 267: DeleteObject (hfont); ! 268: ReleaseDC (hwnd, hdc); ! 269: ! 270: if (startCount != NULL) LocalFree (LocalHandle (startCount)); ! 271: if (endCount != NULL) LocalFree (LocalHandle (endCount)); ! 272: ! 273: break; ! 274: ! 275: ! 276: ! 277: ! 278: ! 279: /**********************************************************************\ ! 280: * WMU_SETNCHAR ! 281: * ! 282: * wParam - nCharPerLine ! 283: * ! 284: \**********************************************************************/ ! 285: case WMU_SETNCHAR: ! 286: SetWindowLong (hwnd, GWLU_NCHAR, (int) wParam); ! 287: InvalidateRect (hwnd, NULL, TRUE); ! 288: break; ! 289: ! 290: /**********************************************************************\ ! 291: * WMU_NEWFONT ! 292: * ! 293: * wParam - Width ! 294: * lParam - Height ! 295: * ! 296: * Create font, select it into the HDC, and reset ranges. ! 297: \**********************************************************************/ ! 298: case WMU_NEWFONT: { ! 299: ! 300: hdc = GetDC(hwnd); ! 301: ! 302: FontWidth = (int) wParam; ! 303: FontHeight = (int) lParam; ! 304: logfont.lfHeight = FontHeight; ! 305: logfont.lfWidth = FontWidth; ! 306: ! 307: hfont = CreateFontIndirect (&logfont); ! 308: hfontOld = SelectObject (hdc, hfont); ! 309: DeleteObject (hfontOld); ! 310: ! 311: ReleaseDC (hwnd, hdc); ! 312: ! 313: ! 314: SetScrollRange (hwnd, SB_HORZ, 0, (nSegments-1), TRUE); ! 315: SetScrollPos (hwnd, SB_HORZ, 0, TRUE); ! 316: ! 317: SendMessage (hwnd, WMU_NEWRANGE, 0,0); ! 318: ! 319: } return TRUE; ! 320: ! 321: ! 322: /**********************************************************************\ ! 323: * WMU_NEWRANGE ! 324: * ! 325: * ! 326: * Range changes, or font size changes, or title status changes. ! 327: \**********************************************************************/ ! 328: case WMU_NEWRANGE: { ! 329: int sqrHeight, sqrWidth; ! 330: TEXTMETRIC tm; ! 331: int i; ! 332: ! 333: hdc = GetDC(hwnd); ! 334: GetTextMetrics (hdc, &tm); ! 335: ReleaseDC (hwnd, hdc); ! 336: ! 337: /* index into the start, end arrays stored in scroll bar */ ! 338: iSeg = GetScrollPos (hwnd, SB_HORZ); ! 339: ! 340: /* Set the window title text to show display range. */ ! 341: wsprintf (buffer, TEXT("[%04x, %04x]"), ! 342: (int)startCount[iSeg], ! 343: (int)endCount[iSeg]); ! 344: ! 345: /* if we are supposed to look up the character range name, ! 346: * then step through the ranges stored in the RangeName ! 347: * table. Find the correct one, and reset the buffer string. ! 348: */ ! 349: if (gShowNames) { ! 350: for (i = 0; i< NRANGE; i++) { ! 351: if ((RangeName[i].start <= startCount[iSeg]) && ! 352: ( startCount[iSeg] <= RangeName[i].end)) ! 353: ! 354: wsprintf (buffer, TEXT("%s [%04x, %04x]"), ! 355: RangeName[i].String, ! 356: (int)startCount[iSeg], ! 357: (int)endCount[iSeg]); ! 358: ! 359: } ! 360: } ! 361: SetWindowText (hwnd, buffer); ! 362: ! 363: sqrHeight = tm.tmHeight + tm.tmExternalLeading; ! 364: sqrWidth = tm.tmMaxCharWidth; ! 365: ! 366: SetWindowLong (hwnd, GWLU_SQRHEIGHT,sqrHeight); ! 367: SetWindowLong (hwnd, GWLU_SQRWIDTH, sqrWidth ); ! 368: ! 369: } return TRUE; ! 370: ! 371: ! 372: ! 373: ! 374: ! 375: ! 376: ! 377: ! 378: ! 379: /**********************************************************************\ ! 380: * WM_LBUTTONDOWN ! 381: * ! 382: * Static, shared variables set in WM_LBUTTONDOWN: ! 383: * rDown, hIcon, DragDropChar ! 384: * ! 385: \**********************************************************************/ ! 386: case WM_LBUTTONDOWN: { ! 387: int x,y; ! 388: int nCharPerLine; ! 389: int sqrHeight, sqrWidth; ! 390: nCharPerLine = GetWindowLong (hwnd, GWLU_NCHAR); ! 391: sqrHeight = GetWindowLong (hwnd, GWLU_SQRHEIGHT); ! 392: sqrWidth = GetWindowLong (hwnd, GWLU_SQRWIDTH ); ! 393: ! 394: ! 395: ! 396: x = (int)LOWORD (lParam); ! 397: y = (int)HIWORD (lParam); ! 398: ! 399: index = transXYtoIndex (x,y, sqrWidth, sqrHeight, nCharPerLine); ! 400: ! 401: /* verify that the index is within the shown segment range */ ! 402: iSeg= GetScrollPos (hwnd, SB_HORZ); ! 403: if (index > (endCount[iSeg]- startCount[iSeg])) return 0; ! 404: ! 405: DragDropChar = index + startCount[iSeg]; ! 406: ! 407: transIndextoRect (index, &rDown, sqrWidth, sqrHeight, nCharPerLine); ! 408: ! 409: hdc = GetDC (hwnd); ! 410: InvertRect (hdc, &rDown); ! 411: ReleaseDC (hwnd, hdc); ! 412: ! 413: ! 414: /* Create a cursor which represents the character. ! 415: * Global variables used: ! 416: * HDC hdcMemXOR; ! 417: * HBITMAP hbmMemXOR; ! 418: * PVOID pbitsXOR, pbitsAND; ! 419: */ ! 420: { ! 421: int cxCursor, cyCursor; ! 422: RECT rect; ! 423: ! 424: cxCursor = GetSystemMetrics (SM_CXCURSOR); ! 425: cyCursor = GetSystemMetrics (SM_CYCURSOR); ! 426: ! 427: rect.left = rect.top = 0; ! 428: rect.right = cxCursor; rect.bottom = cyCursor; ! 429: ! 430: ! 431: FrameRect (hdcMemXOR, &rect, GetStockObject (BLACK_BRUSH)); ! 432: InflateRect (&rect, -1, -1); ! 433: FillRect (hdcMemXOR, &rect, GetStockObject (LTGRAY_BRUSH)); ! 434: FrameRect (hdcMemXOR, &rect, GetStockObject (GRAY_BRUSH)); ! 435: InflateRect (&rect, -1, -1); ! 436: SelectObject (hdcMemXOR, GetStockObject (WHITE_PEN)); ! 437: MoveToEx (hdcMemXOR, rect.right, rect.top, NULL); ! 438: LineTo (hdcMemXOR,rect.left, rect.top); ! 439: LineTo (hdcMemXOR,rect.left, rect.bottom); ! 440: ! 441: ExtTextOut(hdcMemXOR, cxCursor/2,0, ETO_CLIPPED, &rect, ! 442: (LPCWSTR)&DragDropChar, 1, NULL); ! 443: ! 444: GetBitmapBits (hbmMemXOR, cxCursor*cyCursor/2, pbitsXOR); ! 445: ! 446: hIcon = CreateIcon( GetModuleHandle(NULL), ! 447: cxCursor,cyCursor, 1,4, ! 448: pbitsAND, ! 449: pbitsXOR); ! 450: ! 451: SetCursor ((HCURSOR)hIcon); ! 452: } ! 453: ! 454: ! 455: ! 456: GdiFlush (); ! 457: SetCapture (hwnd); ! 458: } break; ! 459: ! 460: /**********************************************************************\ ! 461: * WM_LBUTTONUP ! 462: * ! 463: * Static, shared variables set in WM_LBUTTONDOWN: ! 464: * rDown, hIcon, DragDropChar ! 465: * ! 466: \**********************************************************************/ ! 467: case WM_LBUTTONUP: { ! 468: POINT p; ! 469: HWND hwndTarget, hwndTitle; ! 470: #define NUMCHARS 255 ! 471: TCHAR buffer[NUMCHARS]; ! 472: ! 473: ! 474: if (GetCapture() == hwnd) { ! 475: ! 476: p.x = (int)(short)LOWORD (lParam); ! 477: p.y = (int)(short)HIWORD (lParam); ! 478: ! 479: ClientToScreen (hwnd, &p); ! 480: hwndTarget = WindowFromPoint (p); ! 481: ! 482: if ((GetWindowThreadProcessId (hwnd, NULL)) != ! 483: (GetWindowThreadProcessId (hwndTarget, NULL))) { ! 484: ! 485: /* hack. unipad has a client window which gets the chars, ! 486: * but we want to display the frame windows text (title bar), ! 487: * so try to get the parent of the target for Title purposes. ! 488: */ ! 489: hwndTitle = (GetParent(hwndTarget)) ? GetParent(hwndTarget) : hwndTarget; ! 490: GetWindowText (hwndTitle, buffer, NUMCHARS); ! 491: ! 492: SendMessage (hwndTarget, WM_CHAR, (WPARAM) DragDropChar, 0); ! 493: SendMessage (hwndStatus, WMU_CHARACTER, ! 494: (WPARAM) DragDropChar, (LPARAM)hwndTarget); ! 495: SendMessage (hwndStatus, WMU_SETTARGETNAME, ! 496: (WPARAM) IsWindowUnicode (hwndTarget), (LPARAM)buffer); ! 497: } /* end different process */ ! 498: ! 499: Beep (40,40); ! 500: ! 501: hdc = GetDC (hwnd); ! 502: InvertRect (hdc, &rDown); ! 503: ReleaseDC (hwnd, hdc); ! 504: GdiFlush (); ! 505: ReleaseCapture (); ! 506: SetCursor ((HCURSOR)LoadCursor (NULL, IDC_ARROW)); ! 507: DestroyIcon (hIcon); ! 508: } ! 509: } break; ! 510: ! 511: ! 512: ! 513: /**********************************************************************\ ! 514: * WM_HSCROLL ! 515: * ! 516: * Step through the character ranges. ! 517: * In every case, inform the window the range has changed, ! 518: * and invalidate it to force a repaint. ! 519: \**********************************************************************/ ! 520: case WM_HSCROLL: ! 521: ! 522: switch (LOWORD(wParam)){ ! 523: int OldPos, NewPos; ! 524: ! 525: case SB_PAGEDOWN: ! 526: case SB_LINEDOWN: ! 527: OldPos = GetScrollPos (hwnd, SB_HORZ); ! 528: SetScrollPos (hwnd, SB_HORZ, (OldPos+1), TRUE); ! 529: SendMessage (hwnd,WMU_NEWRANGE, 0,0); ! 530: InvalidateRect (hwnd, NULL, TRUE); ! 531: break; ! 532: ! 533: case SB_PAGEUP: ! 534: case SB_LINEUP: ! 535: OldPos = GetScrollPos (hwnd, SB_HORZ); ! 536: SetScrollPos (hwnd, SB_HORZ, (OldPos-1), TRUE); ! 537: SendMessage (hwnd,WMU_NEWRANGE, 0,0); ! 538: InvalidateRect (hwnd, NULL, TRUE); ! 539: break; ! 540: ! 541: case SB_THUMBPOSITION: ! 542: OldPos = GetScrollPos (hwnd, SB_HORZ); ! 543: NewPos = HIWORD (wParam); ! 544: SetScrollPos (hwnd, SB_HORZ, NewPos, TRUE); ! 545: SendMessage (hwnd,WMU_NEWRANGE, 0,0); ! 546: InvalidateRect (hwnd, NULL, TRUE); ! 547: break; ! 548: ! 549: } ! 550: ! 551: break; ! 552: ! 553: ! 554: ! 555: ! 556: ! 557: ! 558: ! 559: /**********************************************************************\ ! 560: * WM_SIZE ! 561: * ! 562: \**********************************************************************/ ! 563: case WM_SIZE: ! 564: /* make sure that scroll metrics are ok */ ! 565: SendMessage (hwnd, WMU_NEWRANGE, 0,0); ! 566: ! 567: break; /* fall through to MDIChildProc */ ! 568: ! 569: ! 570: /**********************************************************************\ ! 571: * WM_PAINT ! 572: * ! 573: \**********************************************************************/ ! 574: case WM_PAINT: { ! 575: HDC hdc; ! 576: PAINTSTRUCT ps; ! 577: RECT rect; ! 578: POINT point; ! 579: int i; ! 580: USHORT start, end; ! 581: WCHAR outChar; ! 582: USHORT codepoint; ! 583: int nCharPerLine; ! 584: int sqrHeight, sqrWidth; ! 585: nCharPerLine = GetWindowLong (hwnd, GWLU_NCHAR); ! 586: sqrHeight = GetWindowLong (hwnd, GWLU_SQRHEIGHT); ! 587: sqrWidth = GetWindowLong (hwnd, GWLU_SQRWIDTH ); ! 588: ! 589: ! 590: hdc = BeginPaint(hwnd, &ps); ! 591: SetBkMode (hdc, TRANSPARENT); ! 592: ! 593: iSeg= GetScrollPos (hwnd, SB_HORZ); ! 594: start = startCount[iSeg]; ! 595: end = endCount[iSeg]; ! 596: ! 597: /* ensure that we are in a valid range... some fonts have problems */ ! 598: if (start != 0xffff) ! 599: ! 600: for (codepoint = start, i=0; codepoint<=end; codepoint++,i++) { ! 601: ! 602: /* paint box and frame it */ ! 603: transIndextoRect (i, &rect, sqrWidth, sqrHeight, nCharPerLine); ! 604: InflateRect (&rect, -1, -1); ! 605: FillRect (hdc, &rect, GetStockObject (LTGRAY_BRUSH)); ! 606: InflateRect (&rect, 1, 1); ! 607: FrameRect (hdc, &rect, GetStockObject (GRAY_BRUSH)); ! 608: InflateRect (&rect, -1, -1); ! 609: SelectObject (hdc, GetStockObject (WHITE_PEN)); ! 610: MoveToEx (hdc, rect.right, rect.top, NULL); ! 611: LineTo (hdc,rect.left, rect.top); ! 612: LineTo (hdc,rect.left, rect.bottom); ! 613: ! 614: ! 615: ! 616: /* set point that we will draw glyph at */ ! 617: point.x = (rect.right + rect.left)/2; ! 618: point.y = rect.top; ! 619: SetTextAlign (hdc, TA_CENTER | TA_TOP); ! 620: SetTextColor (hdc, PALETTEINDEX (0)); ! 621: ! 622: ! 623: /* special case the non-spacing diacritic marks. U+0300 -> U+036F ! 624: * Write a space first, for them to 'modify.' ! 625: */ ! 626: if ( (0x0300 <= codepoint) && (codepoint <= 0x036F) ) { ! 627: outChar = (WCHAR) 0x0020; ! 628: TextOutW (hdc, 0,0, &outChar, 1); ! 629: } ! 630: ! 631: outChar = (WCHAR) codepoint; ! 632: ExtTextOut(hdc, point.x, point.y, ETO_CLIPPED, &rect, (LPCWSTR)&outChar, 1, NULL); ! 633: ! 634: ! 635: ! 636: /* fill in unicode code point in hex */ ! 637: if (gShowhex) { ! 638: int nchar; ! 639: HANDLE hfonttemp; ! 640: ! 641: nchar = wsprintf (buffer, TEXT("%04x"), (int) codepoint); ! 642: hfonttemp = SelectObject (hdc,GetStockObject (SYSTEM_FIXED_FONT)); ! 643: ! 644: point.y = rect.bottom; ! 645: SetTextAlign (hdc, TA_CENTER | TA_BOTTOM); ! 646: SetTextColor (hdc, PALETTEINDEX (5)); ! 647: ! 648: TextOut( hdc, point.x, point.y, ! 649: buffer, nchar); ! 650: SelectObject (hdc,hfonttemp); ! 651: } ! 652: ! 653: ! 654: } /* end for */ ! 655: ! 656: EndPaint (hwnd, &ps); ! 657: } return FALSE; /* end WM_PAINT */ ! 658: ! 659: ! 660: ! 661: ! 662: } /* end switch */ ! 663: ! 664: return (DefMDIChildProc(hwnd, message, wParam, lParam)); ! 665: } ! 666: ! 667: ! 668: ! 669: ! 670: /**************************************************************************\ ! 671: * ! 672: * Need a mapping between the (x,y) pair, and the index of the square on ! 673: * the window. Two routines provide this... one for each direction. ! 674: * ! 675: \**************************************************************************/ ! 676: ! 677: /**********************************************************************\ ! 678: * transXYtoIndex ! 679: * ! 680: * Given x & y values, return the index. ! 681: * ! 682: \**********************************************************************/ ! 683: int transXYtoIndex (int x, int y, ! 684: int sqrWidth, int sqrHeight, int nCharPerLine) ! 685: { ! 686: x /= sqrWidth; ! 687: if (x < 0) x = 0; ! 688: if (x >= nCharPerLine) x = nCharPerLine-1; ! 689: ! 690: y /= sqrHeight; ! 691: if (y < 0) y = 0; ! 692: ! 693: return ( (y * nCharPerLine) + x); ! 694: } ! 695: ! 696: ! 697: /**********************************************************************\ ! 698: * transIndextoRect ! 699: * ! 700: * Given an index, i.e. the number of one of the squares on the display ! 701: * window, fill in the rectangle structure. ! 702: * ! 703: \**********************************************************************/ ! 704: int transIndextoRect (int index, PRECT pr, ! 705: int sqrWidth, int sqrHeight, int nCharPerLine) ! 706: { ! 707: int x,y; ! 708: ! 709: x = index % nCharPerLine; ! 710: y = index / nCharPerLine; ! 711: ! 712: pr->left = x*sqrWidth; ! 713: pr->top = y*sqrHeight; ! 714: pr->right = pr->left +sqrWidth; ! 715: pr->bottom = pr->top +sqrHeight; ! 716: ! 717: return TRUE; ! 718: } ! 719: ! 720: ! 721: ! 722: ! 723: ! 724: ! 725: /**************************************************************************\ ! 726: * ! 727: * All of the code below is used for parsing 'font data.' It will only ! 728: * make sense if you have a copy of the True Type font spec. In short, ! 729: * we grab the 'cmap' table, look through it for a subtable, and then ! 730: * get two parallel arrays from the subtable. Complications arise because ! 731: * the true type data is 'BIG ENDIAN' and NT is being run 'little endian.' ! 732: * For this reason, once we locate the short or long, we call Swap* to ! 733: * change the byte ordering. ! 734: * ! 735: \**************************************************************************/ ! 736: ! 737: ! 738: VOID SwapShort (PUSHORT); ! 739: VOID SwapULong (PULONG); ! 740: ! 741: ! 742: ! 743: typedef struct tagTABLE{ ! 744: USHORT platformID; ! 745: USHORT encodingID; ! 746: ULONG offset; ! 747: } TABLE, *PTABLE; ! 748: ! 749: typedef struct tagSUBTABLE{ ! 750: USHORT format; ! 751: USHORT length; ! 752: USHORT version; ! 753: USHORT segCountX2; ! 754: USHORT searchRange; ! 755: USHORT entrySelector; ! 756: USHORT rangeShift; ! 757: } SUBTABLE, *PSUBTABLE; ! 758: ! 759: ! 760: /* 'cmap' is passed in by value in a DWORD */ ! 761: #define CMAPHEX 0x70616d63 ! 762: #define NBYTES 256 ! 763: #define OFFSETERROR 0 ! 764: ! 765: ! 766: ! 767: /**************************************************************************\ ! 768: * ! 769: * function: CountUCSegments() ! 770: * ! 771: * input parameters: ! 772: * hdc - with the logical font set into it. ! 773: * prect - pointer to client rectangle. ! 774: * ! 775: * Global variables: ! 776: * startCount ! 777: * endCount ! 778: * ! 779: * returns: ! 780: * number of UC segments or ! 781: * SEGMENTERROR if there is some kind of error. ! 782: * ! 783: * essential side effect: ! 784: * Fills in global startCount, endCount arrays. ! 785: \**************************************************************************/ ! 786: int CountUCSegments (HDC hdc) ! 787: { ! 788: DWORD cbData; ! 789: USHORT aShort[2]; ! 790: DWORD nBytes; ! 791: USHORT i, nTables; ! 792: PTABLE pTable; ! 793: PSUBTABLE pSubTable; ! 794: ULONG offset,offsetFormat4; ! 795: USHORT segCount; ! 796: BYTE buffer[NBYTES]; ! 797: ! 798: ! 799: ! 800: ! 801: /* find number of "subtables", second long in cmap */ ! 802: nBytes=GetFontData (hdc, CMAPHEX, 0, aShort, 4); ! 803: if (nBytes == GDI_ERROR) { ! 804: MessageBox (NULL, MBGETFONTDATAERR,MBERROR , MBERRORFLAGS); ! 805: return SEGMENTERROR; ! 806: } ! 807: if (nBytes == 0) { ! 808: MessageBox (NULL, TEXT("No 'cmap' table."),MBERROR , MBERRORFLAGS); ! 809: return SEGMENTERROR; ! 810: } ! 811: nTables = aShort[1]; ! 812: SwapShort (&nTables); ! 813: ! 814: ! 815: cbData = nTables * sizeof(TABLE); ! 816: if (cbData >NBYTES) { ! 817: MessageBox (NULL, TEXT("cbData >NBYTES"),MBERROR , MBERRORFLAGS); ! 818: return SEGMENTERROR; ! 819: } ! 820: ! 821: /* get array of subtables information. Check each one for 3,1*/ ! 822: nBytes=GetFontData (hdc, CMAPHEX, 4, buffer, cbData); ! 823: pTable = (PTABLE)buffer; ! 824: offsetFormat4 = OFFSETERROR; ! 825: for (i = 0; i< nTables; i++) { ! 826: ! 827: SwapShort (&(pTable->encodingID)); ! 828: SwapShort (&(pTable->platformID)); ! 829: ! 830: if ((pTable->platformID == 3)&&(pTable->encodingID == 1)) { ! 831: offsetFormat4 = pTable->offset; ! 832: SwapULong (&offsetFormat4); ! 833: break; ! 834: } ! 835: pTable++; ! 836: } ! 837: ! 838: /* verify that we got the correct offset to the FORMAT 4 subtable */ ! 839: if (offsetFormat4 == OFFSETERROR){ ! 840: MessageBox (NULL, TEXT("Can not find 3,1 subtable"),MBERROR , MBERRORFLAGS); ! 841: return SEGMENTERROR; ! 842: } ! 843: ! 844: /* Get the beginning of the subtable, especially the segment count */ ! 845: nBytes=GetFontData (hdc, CMAPHEX, offsetFormat4, buffer, sizeof(SUBTABLE)); ! 846: pSubTable = (PSUBTABLE) buffer; ! 847: SwapShort (&(pSubTable->format)); ! 848: SwapShort (&(pSubTable->segCountX2)); ! 849: ! 850: if (pSubTable->format != 4){ ! 851: MessageBox (NULL, TEXT("format !=4"), MBERROR, MBERRORFLAGS); ! 852: return SEGMENTERROR; ! 853: } ! 854: ! 855: segCount = pSubTable->segCountX2 / 2; ! 856: ! 857: /* Now that we know how many segments that the font contains, ! 858: * free up the old memory, and realloc. the two global arrays. ! 859: */ ! 860: if (startCount != NULL) LocalFree (LocalHandle (startCount)); ! 861: if (endCount != NULL) LocalFree (LocalHandle (endCount)); ! 862: startCount = LocalAlloc (LPTR, segCount * sizeof(USHORT)); ! 863: endCount = LocalAlloc (LPTR, segCount * sizeof(USHORT)); ! 864: ! 865: if ((startCount == NULL) || (endCount == NULL)) { ! 866: MessageBox (NULL, TEXT("LocalAlloc failed"), MBERROR, MBERRORFLAGS); ! 867: return SEGMENTERROR; ! 868: } ! 869: ! 870: /* read in the array of endCount values */ ! 871: offset = offsetFormat4 ! 872: + (7 * sizeof (USHORT)); /* skip constant # bytes in subtable */ ! 873: cbData = segCount * sizeof (USHORT); ! 874: nBytes=GetFontData (hdc, CMAPHEX, offset, endCount, cbData ); ! 875: for (i = 0; i<segCount; i++) ! 876: SwapShort (& (endCount[i])); ! 877: ! 878: /* read in the array of startCount values */ ! 879: offset = offsetFormat4 ! 880: + (7 * sizeof (USHORT)) /* skip constant # bytes in subtable */ ! 881: + (segCount * sizeof (USHORT)) /* skip endCount array */ ! 882: + sizeof (USHORT); /* skip reservedPad */ ! 883: cbData = segCount * sizeof (USHORT); ! 884: nBytes=GetFontData (hdc, CMAPHEX, offset, startCount, cbData ); ! 885: for (i = 0; i<segCount; i++) ! 886: SwapShort (& (startCount[i])); ! 887: ! 888: ! 889: return segCount; ! 890: } ! 891: ! 892: ! 893: ! 894: ! 895: ! 896: ! 897: ! 898: ! 899: ! 900: ! 901: VOID SwapShort (PUSHORT p) ! 902: { ! 903: SHORT temp; ! 904: ! 905: temp =(SHORT)( HIBYTE (*p) + (LOBYTE(*p) << 8)); ! 906: *p = temp; ! 907: } ! 908: ! 909: ! 910: ! 911: VOID SwapULong (PULONG p) ! 912: { ! 913: ULONG temp; ! 914: ! 915: temp = (LONG) ((BYTE) *p); ! 916: temp <<= 8; ! 917: *p >>=8; ! 918: ! 919: temp += (LONG) ((BYTE) *p); ! 920: temp <<= 8; ! 921: *p >>=8; ! 922: ! 923: temp += (LONG) ((BYTE) *p); ! 924: temp <<= 8; ! 925: *p >>=8; ! 926: ! 927: temp += (LONG) ((BYTE) *p); ! 928: *p = temp; ! 929: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.