home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / gdi / fonts / gridfont / grid.cxx < prev    next >
C/C++ Source or Header  |  1994-08-28  |  27KB  |  1,016 lines

  1. #include <windows.h>
  2. #include <windowsx.h>
  3. #include <string.h>
  4. #include "app.h"
  5.  
  6. #include "grid.hxx"
  7.  
  8. // These are global variables set by CFontRange::SetFontRange()
  9. // and used by CTextGrid::SetCharTable(). This is safe as only
  10. // one font is selected at a given time by the program.
  11.  
  12. int             vSegCount;
  13. USHORT *        vStartCount;
  14. USHORT *        vEndCount;
  15.  
  16. CSet   *         vpCSet;
  17.  
  18. //+--------------------------------------------------------
  19. // Class:       CFontSelect
  20. //
  21. // Purpose:     Select/Deselect a font
  22. //
  23. // History:     22-Jan-1993     asmusf  created
  24. //----------------------------------------------------------
  25.  
  26. // pure inline
  27.  
  28. //+--------------------------------------------------------
  29. // Class:       CGridIt
  30. //
  31. // Purpose:     Iterate over a grid
  32. //
  33. // History:     22-Jan-1993     asmusf  created
  34. //----------------------------------------------------------
  35.  
  36. // pure inline
  37.  
  38. //+--------------------------------------------------------
  39. // Class:       CLineGrid
  40. //
  41. // Purpose:     Create an n x m Grid of lines
  42. //
  43. // History:     22-Jan-1993     asmusf  created
  44. //----------------------------------------------------------
  45.  
  46. CLineGrid::CLineGrid(UINT cCol, UINT cRow, SIZE size ) 
  47. {
  48.     _size = size;
  49.     _cCol = cCol;
  50.     _cRow = cRow;
  51.     SetStyle();
  52.     SetWeight();
  53. }
  54.  
  55. void CLineGrid::SetStyle(int iStyle)
  56. {
  57.     _iStyle = iStyle;
  58. }
  59.  
  60. void CLineGrid::SetWeight(int nWeight)
  61. {
  62.     _nWeight = nWeight*20;  // internal twips, API is points
  63. }
  64.  
  65. void CLineGrid::Paint(CCanvas& canvas, RECT rc, POINT pt)
  66. {
  67.     int cx, cy;
  68.     UINT i;
  69.  
  70.     // set up pen
  71.     CBlackPen pen(canvas, _iStyle, _nWeight);
  72.  
  73.     // Draw the grid
  74.     for(cx = pt.x, i=0; i<=_cCol; i++, cx+=_size.cx )
  75.     {
  76.         if( cx >= rc.left && cx <= rc.right )
  77.         {
  78.             canvas.Line(cx, pt.y,
  79.                         cx, pt.y+_cRow*_size.cy);
  80.         }
  81.     }
  82.     for(cy = pt.y, i=0; i<=_cRow; i++, cy+=_size.cy )
  83.     {
  84.         if( cy >= rc.top && cy <= rc.bottom )
  85.         {
  86.             canvas.Line(pt.x,                cy,
  87.                         pt.x+_cCol*_size.cx, cy);
  88.         }
  89.     }
  90. }
  91.  
  92. //+--------------------------------------------------------
  93. // Class:       CTextGrid
  94. //
  95. // Purpose:     Create an n x m grid of textual elements
  96. //
  97. // History:     22-Jan-1993     asmusf  created
  98. //----------------------------------------------------------
  99.  
  100. void CTextGrid::SetFont(HFONT hfont)
  101. {
  102.     _font = hfont;
  103. }
  104.  
  105. void CTextGrid :: Paint(CCanvas& canvas, RECT rc, POINT pt)
  106. {
  107.     // Choose text alignment
  108.     SetTextAlign(HDC(canvas), TA_BASELINE|TA_CENTER);
  109.  
  110.     CFontSelect fs(canvas, _font);
  111.  
  112.     for( CGridIt It( _cCol, _cRow, _size, pt ); !It.Done(); ++It)
  113.     {
  114.         if( It.Cx()+_size.cx > rc.left && It.Cx() < rc.right &&
  115.                 It.Cy()+_size.cy > rc.top && It.Cy() < rc.bottom )
  116.         {
  117.             DrawElement(canvas, It.Cx()+_ptOrg.x, It.Cy()+_ptOrg.y, 
  118.                                 It.Col(), It.Row());
  119.         }
  120.     }
  121. }
  122.  
  123. UINT CTextGrid::Hittest(POINT pt, POINT ptTest)
  124. {
  125.     for( CGridIt It( _cCol, _cRow, _size, pt ); !It.Done(); ++It)
  126.     {
  127.         if( It.Cx() <= ptTest.x && It.Cy() <= ptTest.y  &&
  128.             It.Cx()+_size.cx > ptTest.x && It.Cy() +_size.cy > ptTest.y)
  129.             {
  130.                 return   _cRow* It.Col()+ It.Row() + _iEltOffset;
  131.             }
  132.     }
  133.     return 0xFFFF;
  134. }
  135.  
  136. void CTextGrid::SetCharTable()
  137. {
  138.      USHORT i;
  139.      UINT imin = _iEltOffset;
  140.      UINT imax = imin + _cCol*_cRow - 1;
  141.  
  142.      // Make sure the block is used by the font
  143.      if (_pCharUsed != NULL)
  144.          LocalFree (LocalHandle(_pCharUsed));
  145.      // Allocate buffer and make it not used (LPTR put zero in memory)
  146.      if ((_pCharUsed = (USHORT *)LocalAlloc(LPTR, _cCol*_cRow*sizeof(USHORT))) == NULL)
  147.          return;
  148.      if (imin > vEndCount[vSegCount-1] || imax < vStartCount[0])
  149.          return;
  150.      for (i = 0; i < vSegCount; i++)
  151.          {
  152.          if (imax < vStartCount[i])     // no more useful cmap ranges
  153.              break;
  154.          if (imin <= vEndCount[i] && imax >= vStartCount[i]) // check for include
  155.              {
  156.              UINT icur = imin;
  157.              while (icur++ < vStartCount[i]);  // scan until reaching vStartCount
  158.              icur--;
  159.              while (icur <= imax && icur <= vEndCount[i])
  160.                  _pCharUsed[icur++ - imin] = TRUE;
  161.              }
  162.           }
  163. }    
  164.  
  165. //+--------------------------------------------------------
  166. // Class:       CCharGrid
  167. //
  168. // Purpose:     Create an n x m Grid of single characters
  169. //
  170. // History:     22-Jan-1993     asmusf  created
  171. //----------------------------------------------------------
  172.  
  173. CCharGrid :: CCharGrid(UINT cCol, UINT cRow, SIZE size, UINT iEltOffset) 
  174. {
  175.     _size  = size;
  176.     _cCol  = cCol;
  177.     _cRow  = cRow;
  178.     _iEltOffset = iEltOffset;
  179.     SetTextOrg();
  180. }
  181.  
  182. #define NBSP 0x00A0    // no break space
  183.  
  184. void CCharGrid::DrawElement(CCanvas& canvas, COORD x, COORD y, UINT i, UINT j)
  185. {
  186.     WORD iChar = _cRow*i+j+_iEltOffset;
  187. #ifdef UNICODE
  188.     static CCTypeSet Combining(0,0,C3_NONSPACING || C3_DIACRITIC || C3_VOWELMARK);
  189.     static CCTypeSet Alpha(C1_ALPHA, 0, 0);
  190. #endif
  191.  
  192.     if ( vpCSet && vpCSet->In(iChar) )
  193.     {
  194.         SetTextColor(canvas, RGB(128,0,128));
  195.     }
  196.     if (_pCharUsed == NULL || _pCharUsed[_cRow*i+j]) // if char exists draw it
  197.     {
  198. #ifdef UNICODE
  199.         if( Combining.In(iChar) && !Alpha.In(iChar) )
  200.         {
  201.             TCHAR pch[2] = { iChar,0 };
  202.             CFontSelect fs(canvas, _font);
  203.             //SIZE size;
  204.             //GetTextExtentPoint(canvas, pch, 2, &size);
  205.             //canvas.Text(x, y, pch, 2 );
  206.             canvas.Char(x+_size.cx/4/*+size.cx/2*/,y, iChar);
  207.  
  208.             // set up pen                                                
  209.             CBlackPen pen(canvas, PS_DOT, 0);
  210.             CBrush brush(canvas);
  211.  
  212.             // draw dotted circle
  213.             int r = 7*_size.cx/16;     
  214.             canvas.Circle(x, y-r/2, r);
  215.         }
  216.         else
  217.         {
  218.             canvas.Char(x, y, iChar);
  219.         }
  220. #else
  221.         canvas.Char(x, y, iChar);
  222. #endif
  223.     }
  224.     SetTextColor(canvas, RGB(0,0,0));
  225. }
  226.  
  227. //+--------------------------------------------------------
  228. // Class:       CCodeGrid
  229. //
  230. // Purpose:     Create an n x m Grid, numbered in sequence
  231. //
  232. // History:     22-Jan-1993     asmusf  created
  233. //----------------------------------------------------------
  234. CCodeGrid :: CCodeGrid(UINT cCol, UINT cRow, SIZE size, UINT iEltOffset) 
  235. {
  236.     _size  = size;
  237.     _cCol  = cCol;
  238.     _cRow  = cRow;
  239.     _iEltOffset = iEltOffset;
  240.     SetTextOrg();
  241.     SetFormat();
  242. }
  243.  
  244. void CCodeGrid :: SetFormat(UINT fuFormat, UINT cDigits)
  245. {
  246.     _cDigits = cDigits;
  247.  
  248.     _szFormat[0]='%';
  249.     if( fuFormat == DECIMAL )
  250.     {
  251.         _cDigits = 4;       // Constraint:
  252.                             // This format for Decimal
  253.         _szFormat[1]='3';   // really only works with _cDigits == 4
  254.         _szFormat[2]='d';   // 
  255.         _szFormat[3]=' ';   // (blank padding for better positioning)
  256.     } 
  257.     else // 
  258.     {
  259.         _szFormat[1]='0';
  260.         _szFormat[2]=_cDigits%10+'0';
  261.         _szFormat[3]='X';
  262.     }
  263.     _szFormat[4]='\0';
  264. }
  265.  
  266. void CCodeGrid::DrawElement(CCanvas &canvas, COORD x, COORD y, UINT i, UINT j)
  267. {
  268.      TCHAR sz[10];
  269.      if (_pCharUsed == NULL || _pCharUsed[_cRow*i+j]) // if char exists draw it
  270.          {
  271.          wsprintf( sz,_szFormat, (_cRow*i+j+_iEltOffset));
  272.          canvas.Text(x, y, sz, _cDigits);
  273.          }
  274. }
  275.  
  276.  
  277. //+--------------------------------------------------------
  278. // Class:       CCharBlock
  279. //
  280. // Purpose:     Create an n x m lined block of characters and codes
  281. //
  282. // History:     22-Jan-1993     asmusf  created
  283. //----------------------------------------------------------
  284.  
  285. CCharBlock::CCharBlock(UINT cCol, UINT cRow, UINT iBlockOffset, const CBlockFormat &bf) :
  286.      _Line(cCol, cRow, bf._size),
  287.      _Char(cCol, cRow, bf._size, iBlockOffset),
  288.      _Code(cCol, cRow, bf._size, iBlockOffset)
  289. {
  290.      // LINE GRID
  291.      _Line.SetStyle(PS_SOLID);
  292.  
  293.      // LARGE CHARACTER each cell
  294.      _Char.SetFont(bf._fontChar); 
  295.  
  296.      // CODE POINT label each cell
  297.      _Code.SetTextOrg(bf._size.cx/2, 9*bf._size.cy/10);
  298.      _Code.SetFont(bf._fontCode);
  299.      _Code.SetFormat(HEXADECIMAL,4);
  300. }
  301.  
  302. void CCharBlock::Paint(CCanvas& canvas, RECT rc, POINT pt)
  303. {
  304.     _Line.Paint(canvas, rc, pt);
  305. #ifdef UNICODE            
  306.     _Char.SetCharTable();
  307.     _Code.SetCharTable();
  308. #endif            
  309.     _Char.Paint(canvas, rc, pt);
  310.     _Code.Paint(canvas, rc, pt);
  311. }
  312.  
  313. UINT CCharBlock::Hittest(POINT pt, POINT ptTest)
  314. {
  315.     return _Code.Hittest(pt, ptTest);
  316. }
  317.  
  318. void CCharBlock :: SetFormat(UINT fuFormat)
  319. {
  320.     _Code.SetFormat(fuFormat&DECIMAL,4);
  321. }
  322.  
  323. void CCharBlock::SetFont(HFONT font)
  324. {
  325.     _Char.SetFont(font);
  326. }
  327.  
  328. //+--------------------------------------------------------
  329. // Class:       CBlockFrame
  330. //
  331. // Purpose:     Create an n x m frame around a block of characters
  332. //
  333. // History:     22-Jan-1993     asmusf  created
  334. //----------------------------------------------------------
  335.  
  336. CBlockFrame::CBlockFrame(UINT cCol, UINT cRow, POINT pt, UINT iBlockOffset, 
  337.                                 TCHAR * szHeader, const CFrameFormat &ff):
  338.      CCharBlock(cCol, cRow, iBlockOffset, ff ),
  339.      _size(ff._size),
  340.      _Cols(cCol,    1, ff._size, iBlockOffset/16),
  341.      _cRow(cRow),
  342.      _cCol(cCol)
  343. {
  344.  
  345.      // COLUMN label above first row
  346.      _Cols.SetFormat(HEXADECIMAL,3);
  347.      _Cols.SetFont(ff._fontLabel);      
  348.  
  349.  
  350.      // if not first block on page, suppress row labels
  351.      if( iBlockOffset % 0x100 )
  352.      {
  353.         _pRows = NULL;
  354.      }
  355.      else
  356.      {
  357.         // ROW label to left of first column
  358.         _pRows = new CCodeGrid(1, cRow,  ff._size);
  359.         _pRows->SetFont(ff._fontLabel); 
  360.      }
  361.  
  362.      // BLOCK HEADER
  363.      _szHeader = new TCHAR[lstrlen(szHeader)+sizeof(TCHAR)];
  364.      lstrcpy(_szHeader, szHeader);
  365.      _fontHeader = ff._fontHeader;
  366.  
  367. }
  368.  
  369. CBlockFrame::~CBlockFrame()
  370. {
  371.     delete _pRows;
  372.     delete _szHeader;
  373. }
  374.  
  375.  
  376. void CBlockFrame::Paint(CCanvas& canvas, RECT rc, POINT pt)
  377. {
  378.     Draw(canvas, pt);
  379.     {
  380.         POINT ptCols = {pt.x, pt.y-_size.cy};
  381.         _Cols.Paint(canvas, rc, ptCols);  
  382.     } 
  383.     CCharBlock::Paint(canvas, rc, pt);  
  384.     
  385.     // these two are optional. Test first, then draw
  386.     if(_pRows )
  387.     {   
  388.         POINT ptRows = {pt.x-_size.cx, pt.y};
  389.         _pRows->Paint(canvas, rc, ptRows);
  390.     }   
  391. }
  392.  
  393. void CBlockFrame::Draw(CCanvas& canvas, POINT pt)
  394. {
  395.     UINT dy = 3*_size.cy/2;     // height of short uprights
  396.     UINT cx = _cCol*_size.cx;   
  397.     UINT cy = _cRow*_size.cy;
  398.     RECT rc;
  399.         
  400.     // set up pen
  401.     CBlackPen pen(canvas, PS_SOLID, 40);    // Solid Black 40/20 points
  402.  
  403.     //Draw block divider lines
  404.     
  405.     canvas.Line(pt.x,    pt.y-dy, pt.x,    pt.y+cy);  // left edge
  406.     canvas.Line(pt.x+cx, pt.y-dy, pt.x+cx, pt.y+cy);  // right edge
  407.     canvas.Line(pt.x,    pt.y,    pt.x+cx, pt.y);     // top edge
  408.     canvas.Line(pt.x,    pt.y+cy, pt.x+cx, pt.y+cy);  // bottom
  409.     
  410.     CFontSelect fs(canvas, _fontHeader);
  411.  
  412.     SetTextAlign(canvas, TA_BASELINE|TA_LEFT);
  413.     rc.left = pt.x + _size.cx/12;
  414.     rc.top = pt.y - 6*_size.cy/5;
  415.     rc.right = pt.x + cx - _size.cx/12;
  416.     rc.bottom = pt.y;
  417.     canvas.RCText(&rc,
  418.                   _szHeader,
  419.                  lstrlen(_szHeader));
  420. }
  421.  
  422. // The following Array contains the widhts of the Unicode blocks in
  423. // columns. Each Block has a corresponding entry in the stringtable
  424. // giving its block header. "Unassigned" blocks can span page boun-
  425. // daries. 
  426.  
  427. static UINT aBlockWidth[]=
  428. {
  429.     2,6,2,6,   // 0000
  430.     8,8,       // 0100
  431.     5,6,5,     // 0200
  432.     7,6,3,     // 0300
  433.     16,        // 0400
  434.     3,6,7,     // 0500
  435.     16,        // 0600
  436.     32,        // 0700 - 08FF 
  437.     8,8,       // 0900
  438.     8,8,       // 0A00
  439.     8,8,       // 0B00
  440.     8,8,       // 0C00
  441.     8,8,       // 0D00
  442.     8,8,       // 0E00
  443.     16,        // 0F00
  444.     10,6,         // 1000
  445.     16,           // 1100
  446.     192,       // 1200 - 1DFF
  447.     16,           // 1E00
  448.     16,           // 1F00
  449.     7,3,3,3,   // 2000
  450.     5,4,7,     // 2100
  451.     16,        // 2200
  452.     16,        // 2300
  453.     4,2,10,    // 2400
  454.     8,2,6,     // 2500
  455.     16,        // 2600
  456.     12,4,      // 2700
  457.     128,       // 2800 - 2FFF 
  458.     4,6,6,     // 3000
  459.     3,6,1,6,   // 3100
  460.     16,        // 3200
  461.     16,        // 3300
  462.     144,       // 3400 - 3CFF
  463.     3,13,      // 3D00
  464.     96,        // 3E00 - 43FF
  465.     16,           // 4400
  466.     144,       // 4500 - 4DFF
  467.     82*16,     // 4E00 - 9FFF
  468.     64*16,     // A000 - DFFF
  469.     25*16,     // E000 - F8FF
  470.     32,        // F900 - FAFF
  471.     5,11,       // FB00 
  472.     32,        // FC00 - FDFF 
  473.     2,5,9,     // FE00
  474.     15,1,      // FF00
  475.     200        // Sentinel
  476. };
  477.  
  478. //+--------------------------------------------------------
  479. // Class:       CBlockFormat
  480. //
  481. // Purpose:     Block formatting
  482. //
  483. // History:     22-Jan-1993     asmusf  created
  484. //----------------------------------------------------------
  485.  
  486. CBlockFormat::CBlockFormat() :
  487.     _fontCode    (TEXT("Arial Narrow"), -6),
  488. #ifdef UNICODE
  489.     _fontChar    (TEXT("Lucida Sans Unicode"), -16, TRUE)
  490. #else
  491.     _fontChar    (TEXT("Lucida Sans"), -16, TRUE)
  492. #endif
  493. {
  494. };
  495.  
  496. //+--------------------------------------------------------
  497. // Class:       CFrameFormat
  498. //
  499. // Purpose:     Frame formatting
  500. //
  501. // History:     22-Jan-1993     asmusf  created
  502. //----------------------------------------------------------
  503.  
  504. CFrameFormat::CFrameFormat() :
  505.     _fontHeader  (TEXT("Arial"), -12, TRUE),
  506.     _fontLabel   (TEXT("Arial"), -10, TRUE)
  507. {
  508. }
  509.  
  510. //+--------------------------------------------------------
  511. // Class:       CPageFormat
  512. //
  513. // Purpose:     Page formatting
  514. //
  515. // History:     22-Jan-1993     asmusf  created
  516. //----------------------------------------------------------
  517. CPageFormat::CPageFormat(UINT fuFormat) :
  518.     _fontPageNum (TEXT("Times New Roman"), -10, FALSE)
  519. {
  520.     _size.cx =  4*INCH2/5;
  521.     _size.cy =  INCH2;
  522.  
  523.     SetFormat(fuFormat);
  524. }
  525.  
  526. void CPageFormat::SetFormat(UINT fuFormat)
  527. {
  528.     _fuFormat = fuFormat;
  529.  
  530.     if( fuFormat & PAGEPRINT )
  531.     {
  532.         _pt.x=     INCH2+(INCH2*7)/10;
  533.         _pt.y=     INCH1+(INCH1*7)/10;
  534.     } 
  535.     else
  536.     {
  537.         _pt.x=     INCH2;
  538.         _pt.y=     INCH1;
  539.     }
  540.  
  541.     // locations of headers / footers
  542.     _ptPE[0].x = _pt.x-_size.cx; 
  543.     _ptPE[0].y = _size.cy/2;
  544.     _ptPE[1].x = _pt.x+_size.cx*16; 
  545.     _ptPE[1].y = _size.cy/2;
  546.     _ptPE[2].x = _pt.x+(_size.cx*15)/2;
  547.     _ptPE[2].y = _pt.y+(_size.cy*33)/2;
  548. }
  549.  
  550. //+--------------------------------------------------------
  551. // Class:       CPage
  552. //
  553. // Purpose:     One or more blocks
  554. //
  555. // History:     22-Jan-1993     asmusf  created
  556. //----------------------------------------------------------
  557. CPage::CPage(HINSTANCE hInst, CPageFormat &pf, UINT nPage) :
  558.     _cBlock(0),
  559.     _pf(pf),
  560.     _hInst(hInst),
  561.     _PageHeadL (1, 1, pf._size,nPage*256      ),
  562.     _PageHeadR (1, 1, pf._size,(nPage+1)*256-1),
  563.     _PageNums  (1, 1, pf._size,nPage+1        )        
  564.                                 // page numbers are 1 based on output
  565. {
  566.     // Set up page elementss
  567.  
  568.     _PageHeadL.SetFont(pf._fontLabel);
  569.     _PageHeadR.SetFont(pf._fontLabel);
  570.     _PageNums.SetFont(pf._fontPageNum);
  571.  
  572.     InitPage( nPage);
  573.     SetFormat(_pf._fuFormat);
  574. }
  575.  
  576. CPage::~CPage()
  577. {
  578.     while( _cBlock )
  579.     {
  580.         delete _apBlock[--_cBlock];
  581.     }   
  582. }
  583.  
  584.  
  585.  
  586. void CPage::SetFormat(UINT fuFormat)
  587. {
  588.     // set it
  589.     _pf.SetFormat(fuFormat);
  590.  
  591.     // apply it
  592.     for( UINT i = 0; i < _cBlock ; ++i )
  593.     {
  594.         _apBlock[i]->SetFormat(fuFormat&MASKROOT);
  595.     }
  596.  
  597.     _PageHeadL.SetFormat(HEXADECIMAL, 4);
  598.     _PageHeadR.SetFormat(HEXADECIMAL, 4);
  599.     _PageNums.SetFormat(DECIMAL);
  600. }
  601.  
  602.  
  603. void CPage::Paint(CCanvas& canvas, RECT rc)
  604. {
  605.     for( UINT i = 0; i < _cBlock; ++i )
  606.     {
  607.         _apBlock[i]->Paint(canvas, rc, _aptBlock[i]);
  608.     }
  609.  
  610.     if( _pf._fuFormat & PAGEELEMS )
  611.     {
  612.         _PageHeadL.Paint(canvas, rc, _pf._ptPE[0]);
  613.         _PageHeadR.Paint(canvas, rc, _pf._ptPE[1]);
  614.         _PageNums.Paint (canvas, rc, _pf._ptPE[2]);
  615.     }   
  616. }
  617.  
  618. UINT CPage::Hittest(POINT ptTest)
  619. {
  620.     UINT uHit = 0xFFFF;
  621.  
  622.     for( UINT i = 0; i < _cBlock && uHit ==0xFFFF ; ++i )
  623.     {
  624.         uHit = _apBlock[i]->Hittest(_aptBlock[i], ptTest);
  625.     }
  626.     return uHit;
  627. }
  628.  
  629. //-- protected member functions...
  630.  
  631. UINT CPage::InitPage(UINT nPage)
  632. {
  633.     UINT iEnd = 0;
  634.     TCHAR szBlockHeader[40];
  635.     UINT i;
  636.     POINT ptBlock=_pf._pt;
  637.  
  638.     // Set up blocks
  639.  
  640.     for( i=0; i < sizeof(aBlockWidth)/sizeof(UINT); i++ )
  641.     {
  642.         if( nPage*16 < (iEnd+=aBlockWidth[i]) )
  643.         {
  644.             break;
  645.         }
  646.     }
  647.     UINT iStart = max(nPage*16, iEnd-aBlockWidth[i]);
  648.  
  649.     do
  650.     {
  651.         LoadString(_hInst, i, szBlockHeader, 40);
  652.         _apBlock[_cBlock]= new CBlockFrame(
  653.                   min( aBlockWidth[i],      // grid width in columns
  654.                        (nPage+1)*16-iStart),// (but at most to end of page)
  655.                   16,                       // cRow always 16
  656.                   ptBlock,                  // grid origin
  657.                   iStart*16,                // first char offset
  658.                   szBlockHeader,            // header string
  659.                   _pf);                     // common formatting
  660.  
  661.         _aptBlock[_cBlock] = ptBlock;
  662.         _cBlock++;
  663.  
  664.         ptBlock.x+=_pf._size.cx*aBlockWidth[i];
  665.         iStart=iEnd;
  666.     } 
  667.     while(
  668.             (i++ < sizeof(aBlockWidth)/sizeof(UINT))
  669.                 &&
  670.             ((nPage+1)*16 >= (iEnd+=aBlockWidth[i]))
  671.                 &&
  672.             (_cBlock < 4)  
  673.          );
  674.  
  675.  
  676.     return _cBlock;
  677. }
  678.  
  679.  
  680. void CPage::SetFont(HFONT hfont)
  681. {
  682.     for( UINT i = 0; i < _cBlock ; ++i )
  683.     {
  684.         _apBlock[i]->SetFont(hfont);
  685.     }
  686. }
  687.  
  688. //+--------------------------------------------------------
  689. // Class:       CModel  
  690. //
  691. // Purpose:     Iterator over pages
  692. //
  693. // History:     22-Jan-1993     asmusf  created
  694. //----------------------------------------------------------
  695. CModel::CModel(HINSTANCE hInst, HWND hwnd, UINT fuFormat, UINT fPageMode) :
  696.     _iPage(0),
  697. #ifdef UNICODE
  698.     _macPage(0x100),
  699. #else
  700.     _macPage(1),
  701. #endif
  702.     _pf(fuFormat),
  703.     _hInst(hInst),
  704.     _fPageMode(fPageMode)
  705. {
  706.     _pPage = new CPage(hInst, _pf, _iPage);
  707.     _fr.SetFontRange(hwnd, _pf._fontChar);
  708. }
  709.  
  710. CModel::~CModel()
  711. {
  712.     delete _pPage;      
  713. }
  714.  
  715. void CModel::NextPage()
  716. {
  717.  
  718.     if (_fPageMode == ALLPAGES)
  719.         SetPage(_iPage+=(_iPage+1<_macPage? 1 : 0));
  720.     else
  721.         {
  722.            int iNewPage = _iPage;
  723.         while (!_fr.IsPageUsed(++iNewPage) && iNewPage < (int)_macPage);// scan until first found
  724.         if (iNewPage < (int)_macPage)                               // change only if under boundary
  725.             SetPage(_iPage = (UINT)iNewPage);
  726.         }
  727. }
  728.  
  729. void CModel::PrevPage()
  730. {
  731.     if (_fPageMode == ALLPAGES)
  732.         SetPage(_iPage-=(_iPage? 1 : 0));
  733.     else
  734.         {
  735.            int iNewPage = _iPage;
  736.         while (!_fr.IsPageUsed(--iNewPage) && iNewPage >= 0); // scan until first found
  737.         if (iNewPage >= 0)                                // change only if above boundary
  738.             SetPage(_iPage = (UINT)iNewPage);
  739.         }
  740. }
  741.  
  742. void CModel::NextSection()
  743. {
  744.     _iPage+=(_iPage+16<_macPage? 16 : 0);             // increment by 16 pages
  745.     if (_fPageMode == ALLPAGES || _fr.IsPageUsed(_iPage)) // if in USEDONLY mode and
  746.         SetPage(_iPage);                             // the page is not used
  747.     else
  748.         NextPage();
  749. }                                                     // we skip to the next
  750.  
  751. void CModel::PrevSection()
  752. {
  753.     _iPage-=(_iPage >= 16 ? 16 : 0);
  754.     if (_fPageMode == ALLPAGES || _fr.IsPageUsed(_iPage)) // if in USEDONLY mode and
  755.         SetPage(_iPage);                             // the page is not used
  756.     else
  757.         PrevPage();                                     // we skip to the previous
  758. }
  759.  
  760. void CModel::SetPage(UINT nPage)
  761. {
  762.     delete _pPage;
  763.     _pPage = new CPage(_hInst, _pf, nPage);     
  764. }
  765.  
  766. void CModel::GetFormat(UINT &fuFormat) 
  767. {
  768.     fuFormat=_pf._fuFormat; 
  769. }
  770.  
  771. void CModel::SetFormat(UINT fuFormat) 
  772. {
  773.     _pPage->SetFormat(fuFormat);
  774. }
  775.  
  776. HFONT CModel::GetFont()
  777. {
  778.     return _pf._fontChar;
  779. }
  780.  
  781. BOOL CModel::CreateFont(LOGFONT &lf)
  782. {
  783.     if(_pf._fontChar.Create(lf))
  784.     {
  785.          _pPage->SetFont(_pf._fontChar);
  786.          return TRUE;
  787.     }
  788.     return FALSE;
  789. }
  790.  
  791. BOOL CModel::ChooseFont(HWND hwnd)
  792. {
  793.     if(_pf._fontChar.Choose(hwnd))
  794.     {
  795.          _fr.SetFontRange(hwnd, _pf._fontChar);
  796.          _pPage->SetFont(_pf._fontChar);
  797.          return TRUE;
  798.     }
  799.     return FALSE;
  800. }
  801.  
  802. UINT CModel::Hittest( POINT pt)
  803. {
  804.     return _pPage->Hittest( pt);
  805. }
  806.  
  807. void CModel::GetPageMode(UINT &fPageMode) 
  808. {
  809.     fPageMode = _fPageMode; 
  810. }
  811.  
  812. void CModel::SetPageMode(UINT fPageMode) 
  813. {
  814.     _fPageMode = fPageMode;
  815.     if (fPageMode == USEDONLY && !_fr.IsPageUsed(_iPage))//if the current page is empty
  816.         {
  817.         UINT iCurrentPage = _iPage;
  818.         NextPage();                                    //we skip to next
  819.         if (iCurrentPage == _iPage)                    //if there is no next page
  820.             PrevPage();                                //we go to prev (has to be one)
  821.         }
  822. }
  823.  
  824. void CModel :: SetCSet(CSet * pCSet)
  825. {
  826.     vpCSet = pCSet;
  827. }
  828.  
  829. //+----------------------------------------------------------------------
  830. // Class    CFontRange
  831. //
  832. // Purpose:    Set character coverage of the target font
  833. //
  834. // History:    6-Dec-1993    michelsu created
  835. //-----------------------------------------------------------------------
  836. void CFontRange::SetFontRange(HWND hwnd, HFONT hfont)
  837. {
  838.     CScreenCanvas scanvas(hwnd);     // provide the DC
  839.     CFontSelect fs(scanvas, hfont);
  840.  
  841.     USHORT   i;
  842.  
  843.     for (i=0;i<256;i++)
  844.         _fPageUsed[i]=FALSE;         // assume no page used
  845. #ifdef UNICODE
  846.     if (CountUCSegments(scanvas))    // set page used flag for relevant pages
  847.         for (i=0;i<vSegCount;i++) _fPageUsed[(vStartCount[i] & 0xFF00) >> 8] = TRUE;
  848.     else                             // if the font is not TrueType, set only the 1st page
  849.         _fPageUsed[0] =TRUE;
  850. #else
  851.     _fPageUsed[0] =TRUE;
  852. #endif
  853. }
  854.  
  855. CFontRange::~CFontRange()
  856. {
  857.     if (vStartCount != NULL)
  858.         LocalFree (LocalHandle (vStartCount));
  859.     if (vEndCount != NULL)
  860.         LocalFree (LocalHandle (vEndCount));
  861. }
  862. //+----------------------------------------------------------------------
  863. // Class    CFontRange
  864. //
  865. // Purpose:    Get character coverage of the target font (_pf._fontChar)
  866. //
  867. // History:    6-Dec-1993    michelsu created (borrowed in large from TTFONTS)
  868. //-----------------------------------------------------------------------
  869. BOOL CFontRange::CountUCSegments(HDC hdc)
  870. {
  871. #define CMAPHEX    0x70616d63 // = "cmap" (reversed)
  872. #define NBYTES   256
  873. #define OFFSETERROR 0
  874. #define MBERROR TEXT("Application Error.")
  875. #define MBERRORFLAGS MB_OK | MB_ICONHAND
  876.  
  877. typedef struct tagTABLE{
  878.     USHORT platformID;
  879.     USHORT encodingID;
  880.     ULONG  offset;
  881. } TABLE, *PTABLE;
  882.  
  883. typedef struct tagSUBTABLE{
  884.     USHORT format;
  885.     USHORT length;
  886.     USHORT version;
  887.     USHORT segCountX2;
  888.     USHORT searchRange;
  889.     USHORT entrySelector;
  890.     USHORT rangeShift;
  891. } SUBTABLE, *PSUBTABLE;
  892.  
  893.     DWORD       cbData;
  894.     USHORT      aShort[2];
  895.     DWORD       nBytes;
  896.     USHORT      i, nTables;
  897.     PTABLE      pTable;
  898.     PSUBTABLE   pSubTable;
  899.     ULONG       offset,offsetFormat4;
  900.     BYTE        buffer[NBYTES];
  901.  
  902.     // find number of encoding tables, second long in cmap
  903.     nBytes = GetFontData(hdc, CMAPHEX, 0, aShort, 4);
  904.     if (nBytes == GDI_ERROR || nBytes == 0)    //GDI error or no cmap table
  905.         return FALSE;
  906.     nTables = aShort[1];
  907.     SwapShort (&nTables);
  908.  
  909.     // limit ourself to 32 encoding tables (largely enough)
  910.     cbData = nTables * sizeof(TABLE);
  911.     if (cbData >NBYTES)
  912.         {
  913.         MessageBox (NULL, TEXT("cbData >NBYTES"),MBERROR , MBERRORFLAGS);
  914.         return FALSE;
  915.         }
  916.  
  917.     // get array of encoding tables.
  918.     // Check each one for PlatformId = 3, Encoding ID = 1.
  919.     nBytes=GetFontData (hdc, CMAPHEX, 4, buffer, cbData);
  920.     pTable = (PTABLE)buffer;
  921.     offsetFormat4 = OFFSETERROR;
  922.     for (i = 0; i< nTables; i++)
  923.         {
  924.         SwapShort (&(pTable->encodingID));
  925.         SwapShort (&(pTable->platformID));
  926.         if ((pTable->platformID == 3)&&(pTable->encodingID == 1))
  927.             {
  928.             offsetFormat4 = pTable->offset;
  929.             SwapULong (&offsetFormat4);
  930.             break;
  931.             }
  932.         pTable++;
  933.         }
  934.     if (offsetFormat4 == OFFSETERROR) //Can not find 3,1 subtable 
  935.         return FALSE;
  936.  
  937.     /* Get the beginning of the subtable, especially the segment count */
  938.     nBytes=GetFontData (hdc, CMAPHEX, offsetFormat4, buffer, sizeof(SUBTABLE));
  939.     pSubTable = (PSUBTABLE) buffer;
  940.     SwapShort (&(pSubTable->format));
  941.     SwapShort (&(pSubTable->segCountX2));
  942.     if (pSubTable->format != 4)
  943.         {
  944.         MessageBox (NULL, TEXT("format !=4"), MBERROR, MBERRORFLAGS);
  945.         return FALSE;
  946.         }
  947.     vSegCount = pSubTable->segCountX2 / 2;
  948.  
  949.     /* Now that we know how many segments that the font contains,
  950.      *  free up the old memory, and realloc. the two global arrays.
  951.      */
  952.     if (vStartCount != NULL)
  953.         LocalFree (LocalHandle (vStartCount));
  954.     if (vEndCount != NULL)
  955.         LocalFree (LocalHandle (vEndCount));
  956.     vStartCount = (USHORT *)LocalAlloc (LPTR, vSegCount * sizeof(USHORT));
  957.     vEndCount = (USHORT *)LocalAlloc (LPTR, vSegCount * sizeof(USHORT));
  958.     if ((vStartCount == NULL) || (vEndCount == NULL))
  959.         {
  960.         MessageBox (NULL, TEXT("LocalAlloc failed"), MBERROR, MBERRORFLAGS);
  961.         return FALSE;
  962.         }
  963.  
  964.     /* read in the array of endCount values */
  965.     offset = offsetFormat4
  966.            + (7 * sizeof (USHORT));  /* skip constant # bytes in subtable */
  967.     cbData = vSegCount * sizeof (USHORT);
  968.     nBytes=GetFontData (hdc, CMAPHEX, offset, vEndCount, cbData );
  969.     for (i = 0; i<vSegCount; i++)
  970.         SwapShort (& (vEndCount[i]));
  971.  
  972.     /* read in the array of startCount values */
  973.     offset = offsetFormat4
  974.            + (7 * sizeof (USHORT))   /* skip constant # bytes in subtable */
  975.            + (vSegCount * sizeof (USHORT)) /* skip endCount array */
  976.            + sizeof (USHORT);             /* skip reservedPad */
  977.     cbData = vSegCount * sizeof (USHORT);
  978.     nBytes=GetFontData (hdc, CMAPHEX, offset, vStartCount, cbData );
  979.     for (i = 0; i<vSegCount; i++)
  980.         SwapShort (& (vStartCount[i]));
  981.  
  982.     return TRUE;
  983. }
  984.  
  985.  
  986. void CFontRange::SwapShort (PUSHORT p)
  987. {
  988. SHORT temp;
  989.  
  990.     temp =(SHORT)( HIBYTE (*p) + (LOBYTE(*p) << 8));
  991.     *p = temp;
  992. }
  993.  
  994.  
  995.  
  996. void CFontRange::SwapULong (PULONG p)
  997. {
  998. ULONG temp;
  999.  
  1000.     temp = (LONG) ((BYTE) *p);
  1001.     temp <<= 8;
  1002.     *p >>=8;
  1003.  
  1004.     temp += (LONG) ((BYTE) *p);
  1005.     temp <<= 8;
  1006.     *p >>=8;
  1007.  
  1008.     temp += (LONG) ((BYTE) *p);
  1009.     temp <<= 8;
  1010.     *p >>=8;
  1011.  
  1012.     temp += (LONG) ((BYTE) *p);
  1013.     *p = temp;
  1014. }
  1015.             
  1016.