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

Windows编程

开发平台:

Visual C++

  1. /******************************************************************************
  2. *       This is a part of the Microsoft Source Code Samples. 
  3. *       Copyright (C) 1993-1997 Microsoft Corporation.
  4. *       All rights reserved. 
  5. *       This source code is only intended as a supplement to 
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the 
  8. *       Microsoft samples programs.
  9. ******************************************************************************/
  10. /****************************** Module Header *******************************
  11. * Module Name: TPAINT.C
  12. *
  13. * Paint functions
  14. *
  15. * Functions:
  16. *
  17. * GetTextExtent()
  18. * gtab_updatecontig()
  19. * gtab_delcr()
  20. * gtab_updateline()
  21. * gtab_updatecontig()
  22. * gtab_boxcell()
  23. * gtab_paintcell()
  24. * gtab_paint()
  25. * gtab_vsep()
  26. * gtab_hsep()
  27. * gtab_drawvertline()
  28. * gtab_invertsel()
  29. * Comments:
  30. *
  31. * See table.h for interface design.
  32. *
  33. ****************************************************************************/
  34. #include <string.h>
  35. #include <windows.h>
  36. #include <commdlg.h>
  37. #include "gutils.h"
  38. #include "table.h"
  39. #include "tpriv.h"
  40. /***************************************************************************
  41.  * Function: GetTextExtent
  42.  *
  43.  * Purpose:
  44.  * 
  45.  * Calls GetTextExtentPoint - for ease of porting.
  46.  */
  47.  int
  48. GetTextExtent(HDC hdc, LPSTR text, int len)
  49. {
  50.     SIZE sz;
  51.     GetTextExtentPoint(hdc, text, len, &sz);
  52.     return(sz.cx);
  53. }
  54. void gtab_updatecontig(HWND hwnd, lpTable ptab, int line, int cell1, int count);
  55. /***************************************************************************
  56.  * Function: gtab_delcr
  57.  *
  58.  * Purpose:
  59.  *
  60.  * change all cr/lf chars in input text to spaces 
  61.  */
  62. void gtab_delcr(LPSTR ptext)
  63. {
  64.         LPSTR chp;
  65.         if (ptext == NULL) {
  66.                 return;
  67.         }
  68.         for(chp = ptext; (chp = strchr(chp, 'r')) != NULL; ) {
  69.                 *chp = ' ';
  70.         }
  71.         for(chp = ptext; (chp = strchr(chp, 'n')) != NULL; ) {
  72.                 *chp = ' ';
  73.         }
  74. }
  75. /***************************************************************************
  76.  * Function: gtab_updateline
  77.  *
  78.  * Purpose:
  79.  *
  80.  * Ensures that all visible cells in the given line have valid
  81.  * text and property contents. loop through the cells, picking out
  82.  * contiguous blocks of visible, invalid cells and call
  83.  * gtab_updatecontig to update these from the owner window.
  84.  */
  85. void
  86. gtab_updateline(HWND hwnd, lpTable ptab, int line)
  87. {
  88.         lpCellPos ppos;
  89.         int cell1, cellcount;
  90.         lpLineData pline;
  91.         lpCellData cd;
  92.         int i;
  93.         pline = &ptab->pdata[line];
  94.         cell1 = 0;
  95.         cellcount = 0;
  96.         for (i = 0; i < ptab->hdr.ncols; i++) {
  97.                 ppos = &ptab->pcellpos[i];
  98.                 cd = &pline->pdata[i];
  99.                 if (ppos->clipstart < ppos->clipend) {
  100.                         if ((cd->flags & CELL_VALID) == 0) {
  101.                                 /* add a cell to the list to be updated*/
  102.                                 if (cellcount++ == 0) {
  103.                                         cell1 = i;
  104.                                 }
  105.                         } else {
  106.                                 /* this cell already valid - so end of
  107.                                  * a contig block. if the contig
  108.                                  * block just ended contained cells to update,
  109.                                  * do it now
  110.                                  */
  111.                                 if (cellcount > 0) {
  112.                                         gtab_updatecontig(hwnd, ptab,
  113.                                           line, cell1, cellcount);
  114.                                 }
  115.                                 cellcount = 0;
  116.                         }
  117.                 }
  118.                 /* cell not visible - end of a contig block. If it was a
  119.                  * non-empty contig block, then update it now.
  120.                  */
  121.                 if (cellcount > 0)  {
  122.                         gtab_updatecontig(hwnd, ptab, line, cell1, cellcount);
  123.                         cellcount = 0;  
  124.                 }
  125.         }
  126.         if (cellcount > 0) {
  127.                 gtab_updatecontig(hwnd, ptab, line, cell1, cellcount);
  128.                 cellcount = 0;
  129.         }
  130. }
  131. /***************************************************************************
  132.  * Function: gtab_updatecontig
  133.  *
  134.  * Purpose:
  135.  *
  136.  * Updates a contiguous block of invalid cells by calling the owner window
  137.  */
  138. void
  139. gtab_updatecontig(HWND hwnd, lpTable ptab, int line, int cell1, int count)
  140. {
  141.         lpLineData pline;
  142.         lpCellData cd;
  143.         CellDataList list;
  144.         lpProps colprops;
  145.         int i;
  146.         pline = &ptab->pdata[line];
  147.         cd = &pline->pdata[cell1];
  148.         list.id = ptab->hdr.id;
  149.         list.row = gtab_linetorow(hwnd, ptab, line);
  150.         list.startcell = cell1;
  151.         list.ncells = count;
  152.         list.plist = cd;
  153.         /* clear out prop flags */
  154.         for (i = 0; i < count; i++) {
  155.                 cd[i].props.valid = 0;
  156.                 if (cd[i].nchars > 0) {
  157.                         cd[i].ptext[0] = '';
  158.                 }
  159.         }
  160.         if (list.row < ptab->hdr.nrows) {
  161.                 gtab_sendtq(hwnd, TQ_GETDATA, (long) (LPSTR) &list);
  162.         }
  163.         /* for each cell, mark valid and set properties */
  164.         for (i = 0; i < count; i++) {
  165.                 cd[i].flags |= CELL_VALID;
  166.                 gtab_delcr(cd[i].ptext);
  167.                 /* fetch properties from hdr and colhdr */
  168.                 colprops = &ptab->pcolhdr[i + cell1].props;
  169.                 if (!(cd[i].props.valid & P_FCOLOUR)) {
  170.                         if (colprops->valid & P_FCOLOUR) {
  171.                                 cd[i].props.valid |= P_FCOLOUR;
  172.                                 cd[i].props.forecolour = colprops->forecolour;
  173.                         } else if (ptab->hdr.props.valid & P_FCOLOUR) {
  174.                                 cd[i].props.valid |= P_FCOLOUR;
  175.                                 cd[i].props.forecolour =
  176.                                         ptab->hdr.props.forecolour;
  177.                         }
  178.                 }
  179.                 if (!(cd[i].props.valid & P_BCOLOUR)) {
  180.                         if (colprops->valid & P_BCOLOUR) {
  181.                                 cd[i].props.valid |= P_BCOLOUR;
  182.                                 cd[i].props.backcolour = colprops->backcolour;
  183.                         } else if (ptab->hdr.props.valid & P_BCOLOUR) {
  184.                                 cd[i].props.valid |= P_BCOLOUR;
  185.                                 cd[i].props.backcolour =
  186.                                         ptab->hdr.props.backcolour;
  187.                         }
  188.                 }
  189.                 if (!(cd[i].props.valid & P_FONT)) {
  190.                         if (colprops->valid & P_FONT) {
  191.                                 cd[i].props.valid |= P_FONT;
  192.                                 cd[i].props.hFont = colprops->hFont;
  193.                         } else if (ptab->hdr.props.valid & P_FONT) {
  194.                                 cd[i].props.valid |= P_FONT;
  195.                                 cd[i].props.hFont = ptab->hdr.props.hFont;
  196.                         }
  197.                 }
  198.                 if (!(cd[i].props.valid & P_ALIGN)) {
  199.                         if (colprops->valid & P_ALIGN) {
  200.                                 cd[i].props.valid |= P_ALIGN;
  201.                                 cd[i].props.alignment = colprops->alignment;
  202.                         } else if (ptab->hdr.props.valid & P_ALIGN) {
  203.                                 cd[i].props.valid |= P_ALIGN;
  204.                                 cd[i].props.alignment =
  205.                                         ptab->hdr.props.alignment;
  206.                         }
  207.                 }
  208.                 if (!(cd[i].props.valid & P_BOX)) {
  209.                         if (colprops->valid & P_BOX) {
  210.                                 cd[i].props.valid |= P_BOX;
  211.                                 cd[i].props.box = colprops->box;
  212.                         } else if (ptab->hdr.props.valid & P_BOX) {
  213.                                 cd[i].props.valid |= P_BOX;
  214.                                 cd[i].props.box = ptab->hdr.props.box;
  215.                         }
  216.                 }
  217.                 /* you can't set width/height per cell - this
  218.                  * is ignored at cell level.
  219.                  */
  220.         }
  221. }
  222. /***************************************************************************
  223.  * Function: gtab_boxcell
  224.  *
  225.  * Purpose:
  226.  *
  227.  * Draws box around a cell in a table.
  228.  */ 
  229. void
  230. gtab_boxcell(HWND hwnd, HDC hdc, LPRECT rcp, LPRECT pclip, UINT boxmode)
  231. {
  232.         if (boxmode & P_BOXTOP) {
  233.                 MoveToEx(hdc, max(rcp->left, pclip->left),
  234.                         max(rcp->top, pclip->top), NULL);
  235.                 LineTo(hdc, min(rcp->right, pclip->right),
  236.                         max(rcp->top, pclip->top));
  237.         }
  238.         if (boxmode & P_BOXBOTTOM) {
  239.                 MoveToEx(hdc, max(rcp->left, pclip->left),
  240.                         min(rcp->bottom, pclip->bottom), NULL);
  241.                 LineTo(hdc, min(rcp->right, pclip->right),
  242.                         min(rcp->bottom, pclip->bottom));
  243.         }
  244.         if (boxmode & P_BOXLEFT) {
  245.                 MoveToEx(hdc, max(rcp->left, pclip->left),
  246.                         max(rcp->top, pclip->top), NULL);
  247.                 MoveToEx(hdc, max(rcp->left, pclip->left),
  248.                         min(rcp->bottom, pclip->bottom), NULL);
  249.         }
  250.         if (boxmode & P_BOXRIGHT) {
  251.                 MoveToEx(hdc, min(rcp->right, pclip->right),
  252.                         max(rcp->top, pclip->top), NULL);
  253.                 LineTo(hdc, min(rcp->right, pclip->right),
  254.                         min(rcp->bottom, pclip->bottom));
  255.         }
  256. }
  257. /***************************************************************************
  258.  * Function: gtab_paintcell
  259.  *
  260.  * Purpose:
  261.  *
  262.  * Paints a cell.
  263.  */
  264. void
  265. gtab_paintcell(HWND hwnd, HDC hdc, lpTable ptab, int line, int cell)
  266. {
  267.         lpLineData pline;
  268.         lpCellData cd;
  269.         lpCellPos ppos;
  270.         RECT rc, rcbox;
  271.         int cx, x, y, tabwidth;
  272.         UINT align;
  273.         LPSTR chp, tabp;
  274.         DWORD fcol, bkcol;
  275.         HFONT hfont;
  276.         TEXTMETRIC tm;
  277.         HBRUSH hbr;
  278.         /* init pointers to cell text and properties */
  279.         pline = &ptab->pdata[line];
  280.         cd = &pline->pdata[cell];
  281.         ppos = &ptab->pcellpos[cell];
  282.         /* clip all output to this rectangle */
  283.         rc.top = pline->linepos.clipstart;
  284.         rc.bottom = pline->linepos.clipend;
  285.         rc.left = ppos->clipstart;
  286.         rc.right = ppos->clipend;
  287.         /* check cell properties and colours */
  288.         if (cd->props.valid & P_ALIGN) {
  289.                 align = cd->props.alignment;
  290.         } else {
  291.                 align = P_LEFT;
  292.         }
  293.         if (cd->props.valid & P_FONT) {
  294.                 hfont = SelectObject(hdc, cd->props.hFont);
  295.                 GetTextMetrics(hdc, &tm);
  296.                 tabwidth = tm.tmAveCharWidth * 8;
  297.         } else {
  298.                 tabwidth = ptab->avewidth * 8;
  299.         }
  300.         /* set colours if not default */
  301.         if (cd->props.valid & P_FCOLOUR) {
  302.                 fcol = SetTextColor(hdc, cd->props.forecolour);
  303.         }
  304.         if (cd->props.valid & P_BCOLOUR) {
  305.                 /* there is a non-default background colour.
  306.                  * create a brush and fill the entire cell with it
  307.                  */
  308.                 hbr = CreateSolidBrush(cd->props.backcolour);
  309.                 FillRect(hdc, &rc, hbr);
  310.                 DeleteObject(hbr);
  311.                 /* also set colour as background colour for the text */
  312.                 bkcol = SetBkColor(hdc, cd->props.backcolour);
  313.         }
  314.         /* calc offset of text within cell for right-align or centering */
  315.         if (align == P_LEFT) {
  316.                 cx = ptab->avewidth/2;
  317.         } else {
  318.                 if (cd->ptext == NULL) {
  319.                         cx = 0;
  320.                 } else {
  321.                         cx = LOWORD(GetTextExtent(hdc, cd->ptext,
  322.                                         lstrlen(cd->ptext)));
  323.                 }
  324.                 if (align == P_CENTRE) {
  325.                         cx = (ppos->size - cx) / 2;
  326.                 } else {
  327.                         cx = ppos->size - cx - (ptab->avewidth/2);
  328.                 }
  329.         }
  330.         cx += ppos->start;
  331.         /* expand tabs on output */
  332.         x = 0;
  333.         y = pline->linepos.start;
  334.         for (chp = cd->ptext;
  335.             ((chp != NULL) && ((tabp = strchr(chp, 't')) != NULL)); ) {
  336.                 /* perform output upto tab char */
  337.                 ExtTextOut(hdc, x+cx, y, ETO_CLIPPED, &rc, chp, tabp-chp, NULL);
  338.                 
  339.                 /* advance past the tab */
  340.                 x += LOWORD(GetTextExtent(hdc, chp, tabp - chp));
  341.                 x = ( (x + tabwidth) / tabwidth) * tabwidth;
  342.                 chp = ++tabp;
  343.         }
  344.         /*no more tabs - output rest of string */
  345.         if (chp != NULL) {
  346.                 ExtTextOut(hdc, x+cx, y, ETO_CLIPPED, &rc,
  347.                                 chp, lstrlen(chp), NULL);
  348.         }
  349.         /* reset colours to original if not default */
  350.         if (cd->props.valid & P_FCOLOUR) {
  351.                 SetTextColor(hdc, fcol);
  352.         }
  353.         if (cd->props.valid & P_BCOLOUR) {
  354.                 SetBkColor(hdc, bkcol);
  355.         }
  356.         if (cd->props.valid & P_FONT) {
  357.                 SelectObject(hdc, hfont);
  358.         }
  359.         /* now box cell if marked */
  360.         if (cd->props.valid & P_BOX) {
  361.                 if (cd->props.box != 0) {
  362.                         rcbox.top = pline->linepos.start;
  363.                         rcbox.bottom = rcbox.top + pline->linepos.size;
  364.                         rcbox.left = ppos->start;
  365.                         rcbox.right = ppos->start + ppos->size;
  366.                         gtab_boxcell(hwnd, hdc, &rcbox, &rc, cd->props.box);
  367.                 }
  368.         }
  369. }
  370. /***************************************************************************
  371.  * Function: gtab_paint
  372.  *
  373.  * Purpose:
  374.  *
  375.  * Fetch and paint the specified line 
  376.  */
  377. void
  378. gtab_paint(HWND hwnd, HDC hdc, lpTable ptab, int line)
  379. {
  380.         lpCellPos ppos;
  381.         int i;
  382.         gtab_updateline(hwnd, ptab, line);
  383.         for (i = 0; i < ptab->hdr.ncols; i++) {
  384.                 ppos = &ptab->pcellpos[i];
  385.                 if (ppos->clipstart < ppos->clipend) {
  386.                         gtab_paintcell(hwnd, hdc, ptab, line, i);
  387.                 }
  388.         }
  389. }
  390. /***************************************************************************
  391.  * Function: gtab_vsep
  392.  *
  393.  * Purpose:
  394.  *
  395.  */
  396. void
  397. gtab_vsep(HWND hwnd, lpTable ptab, HDC hdc)
  398. {
  399.         int x;
  400.         RECT rc;
  401.         if (ptab->hdr.fixedcols < 1) {
  402.                 return;
  403.         }
  404.         x = ptab->pcellpos[ptab->hdr.fixedcols - 1].clipend+1;
  405.         GetClientRect(hwnd, &rc);
  406.         MoveToEx(hdc, x, rc.top, NULL);
  407.         LineTo(hdc, x, rc.bottom);
  408. }
  409. /***************************************************************************
  410.  * Function: gtab_hsep
  411.  *
  412.  * Purpose:
  413.  */
  414. void
  415. gtab_hsep(HWND hwnd, lpTable ptab, HDC hdc)
  416. {
  417.         int y;
  418.         RECT rc;
  419.         if (ptab->hdr.fixedrows < 1) {
  420.                 return;
  421.         }
  422.         y = ptab->rowheight * ptab->hdr.fixedrows;
  423.         GetClientRect(hwnd, &rc);
  424.         MoveToEx(hdc, rc.left, y-1, NULL);
  425.         LineTo(hdc, rc.right, y-1);
  426. }
  427. /***************************************************************************
  428.  * Function: gtab_drawverline
  429.  *
  430.  * Purpose:
  431.  *
  432.  * Draw in (inverting) the dotted selection lines for tracking a col width
  433.  */
  434. void
  435. gtab_drawvertline(HWND hwnd, lpTable ptab)
  436. {
  437.         RECT rc;
  438.         HDC hdc;
  439.         HPEN hpen;
  440.         hdc = GetDC(hwnd);
  441.         SetROP2(hdc, R2_XORPEN);
  442.         hpen = SelectObject(hdc, hpenDotted);
  443.         GetClientRect(hwnd, &rc);
  444.         MoveToEx(hdc, ptab->trackline1, rc.top, NULL);
  445.         LineTo(hdc, ptab->trackline1, rc.bottom);
  446.         if (ptab->trackline2 != -1) {
  447.                 MoveToEx(hdc, ptab->trackline2, rc.top, NULL);
  448.                 LineTo(hdc, ptab->trackline2, rc.bottom);
  449.         }
  450.         SelectObject(hdc, hpen);
  451.         ReleaseDC(hwnd, hdc);
  452. }
  453.         
  454. /***************************************************************************
  455.  * Function: gtab_invertsel
  456.  *
  457.  * Purpose:
  458.  *
  459.  * Mark the selected line, if visible, in the style chosen by the
  460.  * client app. This can be TM_SOLID, meaning an inversion of
  461.  * the whole selected area or TM_FOCUS, meaning, inversion of the first
  462.  * cell, and then a dotted focus rectangle for the rest.
  463.  *
  464.  * This function inverts either style, and so will turn the selection
  465.  * both on and off.
  466.  */
  467. void
  468. gtab_invertsel(HWND hwnd, lpTable ptab, HDC hdc_in)
  469. {
  470.         HDC hdc;
  471.         int line;
  472.         RECT rc;
  473.         int lastcell;
  474.         /* is row visible on screen ?  */
  475.         line = gtab_rowtoline(hwnd, ptab, ptab->select.startrow);
  476.         if (line < 0) {
  477.                 return;
  478.         }
  479.         /* selection mode includes a flag TM_FOCUS indicating we should
  480.          * use a focus rect instead of the traditional inversion for
  481.          * selections in this table. This interferes with multiple backgrnd
  482.          * colours less.  However we still do inversion for fixedcols.
  483.          */
  484.         lastcell = (int)(ptab->select.startcell + ptab->select.ncells - 1);
  485.         rc.top = ptab->pdata[line].linepos.clipstart;
  486.         rc.bottom = ptab->pdata[line].linepos.clipend;
  487.         /*
  488.          * invert the whole area for TM_SOLID or just the first
  489.          * cell for TM_FOCUS
  490.          */
  491.         rc.left = ptab->pcellpos[ptab->select.startcell].clipstart;
  492.         if (ptab->hdr.selectmode & TM_FOCUS) {
  493.                 rc.right = ptab->pcellpos[ptab->select.startcell].clipend;
  494.         }else {
  495.                 rc.right = ptab->pcellpos[lastcell].clipend;
  496.         }
  497.         if (hdc_in == NULL) {
  498.                 hdc = GetDC(hwnd);
  499.         } else {
  500.                 hdc = hdc_in;
  501.         }
  502.         InvertRect(hdc, &rc);
  503.         /*
  504.          * draw focus rectangle around remaining cells on this line, if there
  505.          * are any
  506.          */
  507.         if (ptab->hdr.selectmode & TM_FOCUS) {
  508.                 if (ptab->select.ncells > 1) {
  509.                         rc.left = ptab->pcellpos[ptab->select.startcell+1].clipstart;
  510.                         rc.right = ptab->pcellpos[lastcell].clipend;
  511.                         DrawFocusRect(hdc, &rc);
  512.                 }
  513.         }
  514.         if (hdc_in == NULL) {
  515.                 ReleaseDC(hwnd, hdc);
  516.         }
  517. }