home *** CD-ROM | disk | FTP | other *** search
- /**************************************************************************\
- * display.c -- module to support the main MDI child windows.
- *
- * Steve Firebaugh
- * Microsoft Developer Support
- * Copyright (c) 1992 Microsoft Corporation
- *
- * window class registered in uniput.c
- * windows are created in main frame window procedure.
- *
- * design: We have one window procedure here for potentially multiple
- * MDI child windows. The nCharPerLine, SqrHeight, and SqrWidth are
- * stored on a per window basis. Also, the window class is registered
- * with the style CS_OWNDC. For this reason, it is possible to select
- * a logical font into the HDC, and it will be there each time you get
- * the DC new for the window. In this way we have a log font for each
- * window without actually doing any work in this module.
- *
- * Some of the data is global, and works for all of the windows. The
- * startcount & endcount arrays are a good example. These are computed
- * once when the font is created, but the values remain the same for each
- * window. Thus we have the following assumption:
- *
- * 1. No fonts will be installed or removed while program is running.
- * (CountUCSegments values remain valid for run time duration).
- *
- *
- * There are WM_USER+ messages to set values for this window, and to
- * notify it of global changes. Looking at the create time, user message
- * stream is helpful. On the WM_CREATE message, we send ourselves a
- * WMU_NEWFONT message to create a logical font and count the number of
- * character ranges (segments). Before returning from this message, we
- * send ourselves a WMU_NEWRANGE message to set the title, and the
- * horizontal scroll bar correctly.
- *
- *
- \**************************************************************************/
- #define UNICODE
-
- #include <windows.h>
- #include "uniput.h"
-
-
- /* global variables store the start and end codepoints for UC ranges. */
- #define MAXSEGMENTS 100
- USHORT endCount[MAXSEGMENTS];
- USHORT startCount[MAXSEGMENTS];
-
- int CountUCSegments (HDC);
- /* error return value from CountUCSegments */
- #define SEGMENTERROR -1
-
-
- /* conversion between (x,y) pairs and rectangle index */
- int transXYtoIndex (int, int, int, int, int);
- int transIndextoRect (int, PRECT, int, int, int);
-
-
- /* window extra bytes for use to store window specific data (see register class) */
- #define GWLU_NCHAR 0
- #define GWLU_SQRHEIGHT 4
- #define GWLU_SQRWIDTH 8
-
-
-
- /* structure for the character range 'name' lookup table. */
- typedef struct tagLookupEntry{
- USHORT start;
- USHORT end;
- TCHAR String[32];
- } LookupEntry;
-
- /* The following data comes straight out of the Addison-Wesley Unicode book. */
- #define NRANGE 24
- LookupEntry RangeName[NRANGE] =
- {{ 0x0000,0x007f, TEXT("ASCII")},
- { 0x0080,0x00ff, TEXT("Latin1 Characters")},
- { 0x0100,0x017f, TEXT("European Latin")},
- { 0x0180,0x01ff, TEXT("Extended Latin")},
- { 0x0200,0x024f, TEXT("<Bad unicode range.>")},
- { 0x0250,0x02af, TEXT("Standard Phonetic")},
- { 0x02b0,0x02ff, TEXT("Modifier Letters")},
- { 0x0300,0x036f, TEXT("Generic Diacritical Marks")},
- { 0x0370,0x03ff, TEXT("Greek")},
- { 0x0400,0x04ff, TEXT("Cyrillic")},
- { 0x0500,0x052f, TEXT("<Bad unicode range.>")},
- { 0x0530,0x058f, TEXT("Armenian")},
- { 0x0590,0x05ff, TEXT("Hebrew")},
- { 0x0600,0x06ff, TEXT("Arabic")},
- { 0x0900,0x1fff, TEXT("<not specified in table.>")},
- { 0x2000,0x206f, TEXT("General Punctutation")},
- { 0x2070,0x209f, TEXT("Superscipts & Subscripts")},
- { 0x20a0,0x20cf, TEXT("Currency Symbols")},
- { 0x20d0,0x20ff, TEXT("Diacritical Marks for Symbols")},
- { 0x2100,0x214f, TEXT("Letterlike Symbols")},
- { 0x2150,0x218f, TEXT("Number Forms")},
- { 0x2190,0x21ff, TEXT("Arrows")},
- { 0x2200,0x22ff, TEXT("Mathematical Operators")},
- { 0x2300,0xffff, TEXT("<not specified in table.>")}};
-
-
-
- /* Global logfont. Used for CreateFontIndirect().
- * also regerenced in the uniput.c file.
- */
- LOGFONT logfont = {
- UCFONTHEIGHT ,
- UCFONTWIDTH ,
- 0 ,
- 0 ,
- 400 ,
- 0 ,
- 0 ,
- 0 ,
- UNICODE_CHARSET ,
- 0 ,
- 0 ,
- 2 ,
- 2 ,
- TEXT("Lucida Sans Unicode")};
-
-
-
-
-
- /**************************************************************************\
- *
- * function: DisplayWndProc()
- *
- * input parameters: normal window procedure parameters.
- *
- \**************************************************************************/
- LRESULT CALLBACK DisplayWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- static HFONT hfont, hfontOld;
-
- static HDC hdc;
- static RECT rect;
- static int iSeg;
- static TCHAR buffer[100];
-
- /* rDown and index used as the user points to a square. */
- static RECT rDown;
- static int index;
-
-
- switch (message) {
-
- /**********************************************************************\
- * WM_CREATE
- *
- * Create font.
- \**********************************************************************/
- case WM_CREATE:
- SendMessage (hwnd, WMU_SETNCHAR, 16, 0);
- SendMessage (hwnd, WMU_NEWFONT, (WPARAM) logfont.lfWidth, (LPARAM) logfont.lfHeight);
- break;
-
-
- /**********************************************************************\
- * WM_DESTROY
- *
- * Get rid of the logical font we create for each display window.
- * relying here on CS_ONWDC
- \**********************************************************************/
- case WM_DESTROY:
- hdc = GetDC (hwnd);
- hfont = SelectObject (hdc, GetStockObject(SYSTEM_FONT));
- ReleaseDC (hwnd, hdc);
- DeleteObject (hfont);
-
- break;
-
-
-
-
-
- /**********************************************************************\
- * WMU_SETNCHAR
- *
- * wParam - nCharPerLine
- *
- \**********************************************************************/
- case WMU_SETNCHAR:
- SetWindowLong (hwnd, GWLU_NCHAR, (int) wParam);
- InvalidateRect (hwnd, NULL, TRUE);
- break;
-
- /**********************************************************************\
- * WMU_NEWFONT
- *
- * wParam - Width
- * lParam - Height
- *
- * Create font, select it into the HDC, and reset ranges.
- \**********************************************************************/
- case WMU_NEWFONT: {
- int nSegments;
-
- hdc = GetDC(hwnd);
-
- logfont.lfHeight = (int) lParam;
- logfont.lfWidth = (int) wParam;
-
- hfont = CreateFontIndirect (&logfont);
- hfontOld = SelectObject (hdc, hfont);
- DeleteObject (hfontOld);
-
- nSegments = CountUCSegments (hdc); /* slow computation */
- ReleaseDC (hwnd, hdc);
-
-
- /* verify that we have SOME ranges to work with */
- if (nSegments == SEGMENTERROR) return FALSE;
-
- /* warn the user if we can't find the right font */
- if (nSegments < 30)
- MessageBox (hwnd,
- TEXT("Working w/ limited codepoint coverage."),
- TEXT("Lucida Sans Unicode font not found."), MB_OK);
-
-
-
- SetScrollRange (hwnd, SB_HORZ, 0, (nSegments-1), TRUE);
- SetScrollPos (hwnd, SB_HORZ, 0, TRUE);
-
- SendMessage (hwnd, WMU_NEWRANGE, 0,0);
-
- } return TRUE;
-
-
- /**********************************************************************\
- * WMU_NEWRANGE
- *
- *
- * Range changes, or font size changes, or title status changes.
- \**********************************************************************/
- case WMU_NEWRANGE: {
- int sqrHeight, sqrWidth;
- TEXTMETRIC tm;
- int i;
-
- hdc = GetDC(hwnd);
- GetTextMetrics (hdc, &tm);
- ReleaseDC (hwnd, hdc);
-
- /* index into the start, end arrays stored in scroll bar */
- iSeg = GetScrollPos (hwnd, SB_HORZ);
-
- /* Set the window title text to show display range. */
- wsprintf (buffer, TEXT("[%04x, %04x]"),
- (int)startCount[iSeg],
- (int)endCount[iSeg]);
-
- /* if we are supposed to look up the character range name,
- * then step through the ranges stored in the RangeName
- * table. Find the correct one, and reset the buffer string.
- */
- if (gShowNames) {
- for (i = 0; i< NRANGE; i++) {
- if ((RangeName[i].start <= startCount[iSeg]) &&
- ( startCount[iSeg] <= RangeName[i].end))
-
- wsprintf (buffer, TEXT("%s [%04x, %04x]"),
- RangeName[i].String,
- (int)startCount[iSeg],
- (int)endCount[iSeg]);
-
- }
- }
- SetWindowText (hwnd, buffer);
-
- sqrHeight = tm.tmHeight + tm.tmExternalLeading;
- sqrWidth = tm.tmMaxCharWidth;
-
- SetWindowLong (hwnd, GWLU_SQRHEIGHT,sqrHeight);
- SetWindowLong (hwnd, GWLU_SQRWIDTH, sqrWidth );
-
- } return TRUE;
-
-
-
-
-
-
-
-
-
- /**********************************************************************\
- \**********************************************************************/
- case WM_LBUTTONDOWN: {
- int x,y;
- int nCharPerLine;
- int sqrHeight, sqrWidth;
- nCharPerLine = GetWindowLong (hwnd, GWLU_NCHAR);
- sqrHeight = GetWindowLong (hwnd, GWLU_SQRHEIGHT);
- sqrWidth = GetWindowLong (hwnd, GWLU_SQRWIDTH );
-
-
-
- x = (int)LOWORD (lParam);
- y = (int)HIWORD (lParam);
-
- index = transXYtoIndex (x,y, sqrWidth, sqrHeight, nCharPerLine);
-
- /* verify that the index is within the shown segment range */
- iSeg= GetScrollPos (hwnd, SB_HORZ);
- if (index > (endCount[iSeg]- startCount[iSeg])) return NULL;
-
-
- transIndextoRect (index, &rDown, sqrWidth, sqrHeight, nCharPerLine);
-
- hdc = GetDC (hwnd);
- InvertRect (hdc, &rDown);
- ReleaseDC (hwnd, hdc);
-
- GdiFlush ();
- SetCapture (hwnd);
- } break;
-
- /**********************************************************************\
- *
- * rDown & index set in WM_LBUTTONDOWN
- *
- \**********************************************************************/
- case WM_LBUTTONUP: {
- POINT p;
-
-
- if (GetCapture() == hwnd) {
-
- p.x = (int)LOWORD (lParam);
- p.y = (int)HIWORD (lParam);
-
- if (PtInRect (&rDown, p)) {
- iSeg= GetScrollPos (hwnd, SB_HORZ);
- index += startCount[iSeg];
- Beep (40,40);
- SendMessage (hwndMain, WMU_CHARACTER, 0, (LPARAM) index);
- }
-
- hdc = GetDC (hwnd);
- InvertRect (hdc, &rDown);
- ReleaseDC (hwnd, hdc);
- GdiFlush ();
- ReleaseCapture ();
-
- }
- } break;
-
-
-
-
-
-
- /**********************************************************************\
- * WM_HSCROLL
- *
- * Step through the character ranges.
- * In every case, inform the window the range has changed,
- * and invalidate it to force a repaint.
- \**********************************************************************/
- case WM_HSCROLL:
-
- switch (LOWORD(wParam)){
- int OldPos, NewPos;
-
- case SB_PAGEDOWN:
- case SB_LINEDOWN:
- OldPos = GetScrollPos (hwnd, SB_HORZ);
- SetScrollPos (hwnd, SB_HORZ, (OldPos+1), TRUE);
- SendMessage (hwnd,WMU_NEWRANGE, 0,0);
- InvalidateRect (hwnd, NULL, TRUE);
- break;
-
- case SB_PAGEUP:
- case SB_LINEUP:
- OldPos = GetScrollPos (hwnd, SB_HORZ);
- SetScrollPos (hwnd, SB_HORZ, (OldPos-1), TRUE);
- SendMessage (hwnd,WMU_NEWRANGE, 0,0);
- InvalidateRect (hwnd, NULL, TRUE);
- break;
-
- case SB_THUMBPOSITION:
- OldPos = GetScrollPos (hwnd, SB_HORZ);
- NewPos = HIWORD (wParam);
- SetScrollPos (hwnd, SB_HORZ, NewPos, TRUE);
- SendMessage (hwnd,WMU_NEWRANGE, 0,0);
- InvalidateRect (hwnd, NULL, TRUE);
- break;
-
- }
-
- break;
-
-
-
-
-
-
-
- /**********************************************************************\
- * WM_SIZE
- *
- \**********************************************************************/
- case WM_SIZE:
- /* make sure that scroll metrics are ok */
- SendMessage (hwnd, WMU_NEWRANGE, 0,0);
-
- break; /* fall through to MDIChildProc */
-
-
- /**********************************************************************\
- * WM_PAINT
- *
- \**********************************************************************/
- case WM_PAINT: {
- HDC hdc;
- PAINTSTRUCT ps;
- RECT rect;
- POINT point;
- int i;
- USHORT start, end;
- WCHAR outChar;
- USHORT codepoint;
- int nCharPerLine;
- int sqrHeight, sqrWidth;
- nCharPerLine = GetWindowLong (hwnd, GWLU_NCHAR);
- sqrHeight = GetWindowLong (hwnd, GWLU_SQRHEIGHT);
- sqrWidth = GetWindowLong (hwnd, GWLU_SQRWIDTH );
-
-
- hdc = BeginPaint(hwnd, &ps);
- SetBkMode (hdc, TRANSPARENT);
-
- iSeg= GetScrollPos (hwnd, SB_HORZ);
- start = startCount[iSeg];
- end = endCount[iSeg];
-
- /* ensure that we are in a valid range... some fonts have problems */
- if (start != 0xffff)
-
- for (codepoint = start, i=0; codepoint<=end; codepoint++,i++) {
-
- /* paint box and frame it */
- transIndextoRect (i, &rect, sqrWidth, sqrHeight, nCharPerLine);
- InflateRect (&rect, -1, -1);
- FillRect (hdc, &rect, GetStockObject (LTGRAY_BRUSH));
- InflateRect (&rect, 1, 1);
- FrameRect (hdc, &rect, GetStockObject (GRAY_BRUSH));
- InflateRect (&rect, -1, -1);
- SelectObject (hdc, GetStockObject (WHITE_PEN));
- MoveToEx (hdc, rect.right, rect.top, NULL);
- LineTo (hdc,rect.left, rect.top);
- LineTo (hdc,rect.left, rect.bottom);
-
-
-
- /* set point that we will draw glyph at */
- point.x = (rect.right + rect.left)/2;
- point.y = rect.top;
- SetTextAlign (hdc, TA_CENTER | TA_TOP);
- SetTextColor (hdc, PALETTEINDEX (0));
-
-
- /* special case the non-spacing diacritic marks. U+0300 -> U+036F
- * Write a space first, for them to 'modify.'
- */
- if ( (0x0300 <= codepoint) && (codepoint <= 0x036F) ) {
- outChar = (WCHAR) 0x0020;
- TextOutW (hdc, 0,0, &outChar, 1);
- }
-
- outChar = (WCHAR) codepoint;
- ExtTextOut(hdc, point.x, point.y, ETO_CLIPPED, &rect, (LPCTSTR)&outChar, 1, NULL);
-
-
-
- /* fill in unicode code point in hex */
- if (gShowhex) {
- int nchar;
- HANDLE hfonttemp;
-
- nchar = wsprintf (buffer, TEXT("%04x"), (int) codepoint);
- hfonttemp = SelectObject (hdc,GetStockObject (SYSTEM_FIXED_FONT));
-
- point.y = rect.bottom;
- SetTextAlign (hdc, TA_CENTER | TA_BOTTOM);
- SetTextColor (hdc, PALETTEINDEX (5));
-
- TextOut( hdc, point.x, point.y,
- buffer, nchar);
- SelectObject (hdc,hfonttemp);
- }
-
-
- } /* end for */
-
- EndPaint (hwnd, &ps);
- } return FALSE; /* end WM_PAINT */
-
-
-
-
- } /* end switch */
-
- return (DefMDIChildProc(hwnd, message, wParam, lParam));
- }
-
-
-
-
- /**************************************************************************\
- *
- * Need a mapping between the (x,y) pair, and the index of the square on
- * the window. Two routines provide this... one for each direction.
- *
- \**************************************************************************/
-
- /**********************************************************************\
- * transXYtoIndex
- *
- * Given x & y values, return the index.
- *
- \**********************************************************************/
- int transXYtoIndex (int x, int y,
- int sqrWidth, int sqrHeight, int nCharPerLine)
- {
- x /= sqrWidth;
- if (x < 0) x = 0;
- if (x >= nCharPerLine) x = nCharPerLine-1;
-
- y /= sqrHeight;
- if (y < 0) y = 0;
-
- return ( (y * nCharPerLine) + x);
- }
-
-
- /**********************************************************************\
- * transIndextoRect
- *
- * Given an index, i.e. the number of one of the squares on the display
- * window, fill in the rectangle structure.
- *
- \**********************************************************************/
- int transIndextoRect (int index, PRECT pr,
- int sqrWidth, int sqrHeight, int nCharPerLine)
- {
- int x,y;
-
- x = index % nCharPerLine;
- y = index / nCharPerLine;
-
- pr->left = x*sqrWidth;
- pr->top = y*sqrHeight;
- pr->right = pr->left +sqrWidth;
- pr->bottom = pr->top +sqrHeight;
-
- return TRUE;
- }
-
-
-
-
-
-
- /**************************************************************************\
- *
- * All of the code below is used for parsing 'font data.' It will only
- * make sense if you have a copy of the True Type font spec. In short,
- * we grab the 'cmap' table, look through it for a subtable, and then
- * get two parallel arrays from the subtable. Complications arise because
- * the true type data is 'BIG ENDIAN' and NT is being run 'little endian.'
- * For this reason, once we locate the short or long, we call Swap* to
- * change the byte ordering.
- *
- \**************************************************************************/
-
-
- VOID SwapShort (PUSHORT);
- VOID SwapULong (PULONG);
-
-
-
- typedef struct tagTABLE{
- USHORT platformID;
- USHORT encodingID;
- ULONG offset;
- } TABLE, *PTABLE;
-
- typedef struct tagSUBTABLE{
- USHORT format;
- USHORT length;
- USHORT version;
- USHORT segCountX2;
- USHORT searchRange;
- USHORT entrySelector;
- USHORT rangeShift;
- } SUBTABLE, *PSUBTABLE;
-
-
- /* 'cmap' is passed in by value in a DWORD */
- #define CMAPHEX 0x636d6170
- #define NBYTES 256
- #define OFFSETERROR 0
-
-
-
- /**************************************************************************\
- *
- * function: CountUCSegments()
- *
- * input parameters:
- * hdc - with the logical font set into it.
- * prect - pointer to client rectangle.
- *
- * Global variables:
- * startCount
- * endCount
- *
- * returns:
- * number of UC segments or
- * SEGMENTERROR if there is some kind of error.
- *
- * essential side effect:
- * Fills in global startCount, endCount arrays.
- \**************************************************************************/
- int CountUCSegments (HDC hdc)
- {
- DWORD cbData;
- USHORT aShort[2];
- DWORD nBytes;
- USHORT i, nTables;
- PTABLE pTable;
- PSUBTABLE pSubTable;
- ULONG offset,offsetFormat4;
- USHORT segCount;
- BYTE buffer[NBYTES];
-
-
-
-
- /* find number of 'subtables', second long in cmap */
- nBytes=GetFontData (hdc, CMAPHEX, 0, aShort, 4);
- if (nBytes == (DWORD)-1) {
- MessageBox (NULL, MBGETFONTDATAERR,MBERROR , MBERRORFLAGS);
- return SEGMENTERROR;
- }
- nTables = aShort[1];
- SwapShort (&nTables);
-
-
- cbData = nTables * sizeof(TABLE);
- if (cbData >NBYTES) {
- MessageBox (NULL, TEXT("cbData >NBYTES"),MBERROR , MBERRORFLAGS);
- return SEGMENTERROR;
- }
-
- /* get array of subtables information. Check each one for 3,1*/
- nBytes=GetFontData (hdc, CMAPHEX, 4, buffer, cbData);
- pTable = (PTABLE)buffer;
- offsetFormat4 = OFFSETERROR;
- for (i = 0; i< nTables; i++) {
-
- SwapShort (&(pTable->encodingID));
- SwapShort (&(pTable->platformID));
-
- if ((pTable->platformID == 3)&&(pTable->encodingID == 1)) {
- offsetFormat4 = pTable->offset;
- SwapULong (&offsetFormat4);
- break;
- }
- pTable++;
- }
-
- /* verify that we got the correct offset to the FORMAT 4 subtable */
- if (offsetFormat4 == OFFSETERROR){
- MessageBox (NULL, TEXT("Can not find 3,1 subtable"),MBERROR , MBERRORFLAGS);
- return SEGMENTERROR;
- }
-
- /* Get the beginning of the subtable, especially the segment count */
- nBytes=GetFontData (hdc, CMAPHEX, offsetFormat4, buffer, sizeof(SUBTABLE));
- pSubTable = (PSUBTABLE) buffer;
- SwapShort (&(pSubTable->format));
- SwapShort (&(pSubTable->segCountX2));
-
- if (pSubTable->format != 4){
- MessageBox (NULL, TEXT("format !=4"), MBERROR, MBERRORFLAGS);
- return SEGMENTERROR;
- }
-
- segCount = pSubTable->segCountX2 / 2;
-
- if (segCount > MAXSEGMENTS){
- MessageBox (NULL, TEXT("segCount > MAXSEGMENTS"), MBERROR, MBERRORFLAGS);
- return SEGMENTERROR;
- }
-
- /* read in the array of endCount values */
- offset = offsetFormat4
- + (7 * sizeof (USHORT)); /* skip constant # bytes in subtable */
- cbData = segCount * sizeof (USHORT);
- nBytes=GetFontData (hdc, CMAPHEX, offset, endCount, cbData );
- for (i = 0; i<segCount; i++)
- SwapShort (& (endCount[i]));
-
- /* read in the array of startCount values */
- offset = offsetFormat4
- + (7 * sizeof (USHORT)) /* skip constant # bytes in subtable */
- + (segCount * sizeof (USHORT)) /* skip endCount array */
- + sizeof (USHORT); /* skip reservedPad */
- cbData = segCount * sizeof (USHORT);
- nBytes=GetFontData (hdc, CMAPHEX, offset, startCount, cbData );
- for (i = 0; i<segCount; i++)
- SwapShort (& (startCount[i]));
-
-
- return segCount;
- }
-
-
-
-
-
-
-
-
-
-
- VOID SwapShort (PUSHORT p)
- {
- SHORT temp;
-
- temp =(SHORT)( HIBYTE (*p) + (LOBYTE(*p) << 8));
- *p = temp;
- }
-
-
-
- VOID SwapULong (PULONG p)
- {
- ULONG temp;
-
- temp = (LONG) ((BYTE) *p);
- temp <<= 8;
- *p >>=8;
-
- temp += (LONG) ((BYTE) *p);
- temp <<= 8;
- *p >>=8;
-
- temp += (LONG) ((BYTE) *p);
- temp <<= 8;
- *p >>=8;
-
- temp += (LONG) ((BYTE) *p);
- *p = temp;
- }
-