home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / windiff / tpaint.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  19KB  |  578 lines

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