GRID.CXX
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:26k
源码类别:

Windows编程

开发平台:

Visual C++

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