tvpaint.c
Upload User: caisha3
Upload Date: 2013-09-21
Package Size: 208739k
Code Size: 23k
Category:

Windows Develop

Development Platform:

Visual C++

  1. #include "ctlspriv.h"
  2. #include "treeview.h"
  3. #include "image.h"
  4. void NEAR TV_GetBackgroundBrush(PTREE pTree, HDC hdc)
  5. {
  6. #ifdef WIN32
  7.     if (pTree->style & WS_DISABLED)
  8.         pTree->hbrBk = FORWARD_WM_CTLCOLORSTATIC(pTree->hwndParent, hdc, pTree->hwnd, SendMessage);
  9.     else
  10.         pTree->hbrBk = FORWARD_WM_CTLCOLOREDIT(pTree->hwndParent, hdc, pTree->hwnd, SendMessage);
  11. #else
  12.     pTree->hbrBk = FORWARD_WM_CTLCOLOR(pTree->hwndParent, hdc, pTree->hwnd,
  13.         (pTree->style & WS_DISABLED)? CTLCOLOR_STATIC : CTLCOLOR_EDIT,
  14.         SendMessage);
  15. #endif
  16. }
  17. // ----------------------------------------------------------------------------
  18. //
  19. //  Draws a horizontal or vertical dotted line from the given (x,y) location
  20. //  for the given length (c).
  21. //
  22. // ----------------------------------------------------------------------------
  23. void NEAR TV_DrawDottedLine(HDC hdc, int x, int y, int c, BOOL fVert)
  24. {
  25.     while (c > 0)
  26.     {
  27.         PatBlt(hdc, x, y, 1, 1, PATCOPY);
  28.         if (fVert)
  29.             y += 2;
  30.         else
  31.             x += 2;
  32.         c -= 2;
  33.     }
  34. }
  35. // ----------------------------------------------------------------------------
  36. //
  37. //  Draws a plus or minus sign centered around the given (x,y) location and
  38. //  extending out from that location the given distance (c).
  39. //
  40. // ----------------------------------------------------------------------------
  41. void NEAR TV_DrawPlusMinus(HDC hdc, int x, int y, int c, HBRUSH hbrSign, HBRUSH hbrBox, HBRUSH hbrBk, BOOL fPlus)
  42. {
  43.     int n;
  44.     int p = (c * 7) / 10;
  45.     n = p * 2 + 1;
  46.     SelectObject(hdc, hbrSign);
  47.     if (p >= 5)
  48.     {
  49.         PatBlt(hdc, x - p, y - 1, n, 3, PATCOPY);
  50.         if (fPlus)
  51.             PatBlt(hdc, x - 1, y - p, 3, n, PATCOPY);
  52.         SelectObject(hdc, hbrBk);
  53.         p--;
  54.         n -= 2;
  55.     }
  56.     PatBlt(hdc, x - p, y, n, 1, PATCOPY);
  57.     if (fPlus)
  58.         PatBlt(hdc, x, y - p, 1, n, PATCOPY);
  59.     n = c * 2 + 1;
  60.     SelectObject(hdc, hbrBox);
  61.     PatBlt(hdc, x - c, y - c, n, 1, PATCOPY);
  62.     PatBlt(hdc, x - c, y - c, 1, n, PATCOPY);
  63.     PatBlt(hdc, x - c, y + c, n, 1, PATCOPY);
  64.     PatBlt(hdc, x + c, y - c, 1, n, PATCOPY);
  65. }
  66. // ----------------------------------------------------------------------------
  67. //
  68. //  Create the bitmaps for the indent area of the tree as follows
  69. //  if  fHasLines &&  fHasButtons --> 7 bitmaps
  70. //  if  fHasLines && !fHasButtons --> 3 bitmaps
  71. //  if !fHasLines &&  fHasButtons --> 2 bitmaps
  72. //
  73. //  sets hStartBmp, hBmp, hdcBits
  74. //
  75. // ----------------------------------------------------------------------------
  76. void NEAR TV_CreateIndentBmps(PTREE pTree)
  77. {
  78.     int  cnt;
  79.     RECT rc;
  80.     HBRUSH hbrOld;
  81.     int xMid, yMid;
  82.     int x, c;
  83.     HBITMAP hBmpOld;
  84.     HDC hdc;
  85.     if (pTree->fRedraw)
  86.         InvalidateRect(pTree->hwnd, NULL, TRUE);
  87.     if (pTree->style & TVS_HASLINES)
  88.     {
  89.         if (pTree->style & TVS_HASBUTTONS)
  90.             cnt = 7;  //   | |-  L   |+ L+  |- L-
  91.         else
  92.             cnt = 3;  //   | |-  L
  93.         if (pTree->style & TVS_LINESATROOT) {
  94.             if (pTree->style & TVS_HASBUTTONS)
  95.                 cnt += 3;    // -  -+ --
  96.             else
  97.                 cnt += 1;    // -
  98.         }
  99.     }
  100.     else if (pTree->style & TVS_HASBUTTONS)
  101.         cnt = 2;
  102.     else
  103.         return;
  104.     if (!pTree->hdcBits)
  105.         pTree->hdcBits = CreateCompatibleDC(NULL);
  106.     hdc = pTree->hdcBits;
  107.     // Get a new background brush, just like an Edit does.
  108.     TV_GetBackgroundBrush(pTree, hdc);
  109.     hBmpOld = pTree->hBmp;
  110.     pTree->hBmp = CreateColorBitmap(cnt * pTree->cxIndent, pTree->cyItem);
  111.     if (hBmpOld) {
  112.         SelectObject(hdc, pTree->hBmp);
  113.         DeleteObject(hBmpOld);
  114.     } else
  115.         pTree->hStartBmp = SelectObject(hdc, pTree->hBmp);
  116.     hbrOld = SelectObject(hdc, g_hbrGrayText);
  117.     rc.top = 0;
  118.     rc.left = 0;
  119.     rc.right = cnt * pTree->cxIndent;
  120.     rc.bottom = pTree->cyItem;
  121.     FillRect(hdc, &rc, pTree->hbrBk);
  122.     x = 0;
  123.     if (pTree->hImageList)
  124.         xMid = (pTree->cxImage - MAGIC_INDENT) / 2;
  125.     else
  126.         xMid = pTree->cxIndent / 2;
  127.     yMid = ((pTree->cyItem / 2) + 1) & ~1;
  128.     c = (min(xMid, yMid)) / 2;
  129.     if (pTree->style & TVS_HASLINES)
  130.     {
  131.         TV_DrawDottedLine(hdc, x + xMid, 0, pTree->cyItem, TRUE);
  132.         x += pTree->cxIndent;
  133.         TV_DrawDottedLine(hdc, x + xMid, 0, pTree->cyItem, TRUE);
  134.         TV_DrawDottedLine(hdc, x + xMid, yMid, pTree->cxIndent - xMid, FALSE);
  135.         x += pTree->cxIndent;
  136.         TV_DrawDottedLine(hdc, x + xMid, 0, yMid, TRUE);
  137.         TV_DrawDottedLine(hdc, x + xMid, yMid, pTree->cxIndent - xMid, FALSE);
  138.         x += pTree->cxIndent;
  139.     }
  140.     if (pTree->style & TVS_HASBUTTONS)
  141.     {
  142.         BOOL fPlus = TRUE;
  143.         x += xMid;
  144. doDrawPlusMinus:
  145.         TV_DrawPlusMinus(hdc, x, yMid, c, g_hbrWindowText, g_hbrGrayText, pTree->hbrBk, fPlus);
  146.         if (pTree->style & TVS_HASLINES)
  147.         {
  148.             TV_DrawDottedLine(hdc, x, 0, yMid - c, TRUE);
  149.             TV_DrawDottedLine(hdc, x + c, yMid, pTree->cxIndent - xMid - c, FALSE);
  150.             TV_DrawDottedLine(hdc, x, yMid + c, yMid - c, TRUE);
  151.             x += pTree->cxIndent;
  152.             TV_DrawPlusMinus(hdc, x, yMid, c, g_hbrWindowText, g_hbrGrayText, pTree->hbrBk, fPlus);
  153.             TV_DrawDottedLine(hdc, x, 0, yMid - c, TRUE);
  154.             TV_DrawDottedLine(hdc, x + c, yMid, pTree->cxIndent - xMid - c, FALSE);
  155.         }
  156.         x += pTree->cxIndent;
  157.         if (fPlus)
  158.         {
  159.             fPlus = FALSE;
  160.             goto doDrawPlusMinus;
  161.         }
  162.         x -= xMid;
  163.     }
  164.     if (pTree->style & TVS_LINESATROOT) {
  165.         // -
  166.         TV_DrawDottedLine(hdc, x + xMid, yMid, pTree->cxIndent - xMid, FALSE);
  167.         x += pTree->cxIndent;
  168.         if (pTree->style & TVS_HASBUTTONS) {
  169.             x += xMid;
  170.             TV_DrawPlusMinus(hdc, x, yMid, c, g_hbrWindowText, g_hbrGrayText, pTree->hbrBk, TRUE);
  171.             TV_DrawDottedLine(hdc, x + c, yMid, pTree->cxIndent - xMid - c, FALSE);
  172.             x += pTree->cxIndent;
  173.             TV_DrawPlusMinus(hdc, x, yMid, c, g_hbrWindowText, g_hbrGrayText, pTree->hbrBk, FALSE);
  174.             TV_DrawDottedLine(hdc, x + c, yMid, pTree->cxIndent - xMid - c, FALSE);
  175.             //  uncomment if there's more to be added
  176.             //x += pTree->cxIndent - xMid;
  177.         }
  178.     }
  179.     if (hbrOld)
  180.         SelectObject(pTree->hdcBits, hbrOld);
  181. }
  182. // ----------------------------------------------------------------------------
  183. //
  184. //  fills in a TV_ITEM structure based by coying data from the item or
  185. //  by calling the callback to get it.
  186. //
  187. //  in:
  188. // hItem item to get TV_ITEM struct for
  189. // mask which bits of the TV_ITEM struct you want (TVIF_ flags)
  190. //  out:
  191. // lpItem TV_ITEM filled in
  192. //
  193. // ----------------------------------------------------------------------------
  194. void NEAR TV_GetItem(PTREE pTree, HTREEITEM hItem, UINT mask, LPTV_ITEM lpItem)
  195. {
  196.     TV_DISPINFO nm;
  197.     if (!hItem || !lpItem)
  198.         return;
  199.     nm.item.mask = 0;
  200.     // We need to check the mask to see if lpItem->pszText is valid
  201.     if (mask & TVIF_TEXT) {
  202.         if (hItem->lpstr == LPSTR_TEXTCALLBACK) {
  203.     nm.item.mask |= TVIF_TEXT;
  204.     // caller had to fill in pszText and cchTextMax with valid data
  205.             nm.item.pszText = lpItem->pszText;
  206.     nm.item.cchTextMax = lpItem->cchTextMax;
  207.     nm.item.pszText[0] = 0;
  208. } else {
  209.     Assert(hItem->lpstr);
  210.     // we could do this but this is dangerous (when responding
  211.     // to TVM_GETITEM we would be giving the app a pointer to our data)
  212.             // lpItem->pszText = hItem->lpstr;
  213.     lstrcpyn(lpItem->pszText, hItem->lpstr, lpItem->cchTextMax);
  214. }
  215.     }
  216.     if (mask & TVIF_IMAGE) {
  217.         if (hItem->iImage == (WORD)I_IMAGECALLBACK)
  218.     nm.item.mask |= TVIF_IMAGE;
  219. else
  220.             lpItem->iImage = hItem->iImage;
  221.     }
  222.     if (mask & TVIF_SELECTEDIMAGE) {
  223.         if (hItem->iSelectedImage == (WORD)I_IMAGECALLBACK)
  224.     nm.item.mask |= TVIF_SELECTEDIMAGE;
  225. else
  226.             lpItem->iSelectedImage = hItem->iSelectedImage;
  227.     }
  228.     if (mask & TVIF_CHILDREN) {
  229. switch (hItem->fKids) {
  230. case KIDS_COMPUTE:
  231.             lpItem->cChildren = hItem->hKids ? 1 : 0;// the actual count doesn't matter
  232.     break;
  233. case KIDS_FORCE_YES:
  234.             lpItem->cChildren = 1;// the actual count doesn't matter
  235.     break;
  236. case KIDS_FORCE_NO:
  237.             lpItem->cChildren = 0;
  238.     break;
  239. case KIDS_CALLBACK:
  240.     nm.item.mask |= TVIF_CHILDREN;
  241.     break;
  242. }
  243.     }
  244.     // copy out constant parameters (and prepare for callback)
  245.     lpItem->state = nm.item.state = hItem->state;
  246.     lpItem->lParam = nm.item.lParam = hItem->lParam;
  247.     // any items need to be filled in by callback?
  248.     if (nm.item.mask & (TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN)) {
  249.         nm.item.hItem = hItem;
  250. SendNotify(pTree->hwndParent, pTree->hwnd, TVN_GETDISPINFO, &nm.hdr);
  251. // copy out things that may have been filled in on the callback
  252. if (nm.item.mask & TVIF_CHILDREN)
  253.     lpItem->cChildren = nm.item.cChildren;
  254. if (nm.item.mask & TVIF_IMAGE)
  255.     lpItem->iImage = nm.item.iImage;
  256.         if (nm.item.mask & TVIF_SELECTEDIMAGE)
  257.     lpItem->iSelectedImage = nm.item.iSelectedImage;
  258. // callback may have redirected pszText to point into its own buffer
  259. if (nm.item.mask & TVIF_TEXT)
  260.     lpItem->pszText = nm.item.pszText;
  261.         if (nm.item.mask & TVIF_STATE)
  262.             lpItem->state = (nm.item.state & nm.item.stateMask) | (lpItem->state & ~nm.item.stateMask);
  263.         if (nm.item.mask & TVIF_DI_SETITEM) {
  264.             if (nm.item.mask & TVIF_TEXT)
  265.                 if (nm.item.pszText && (nm.item.pszText != LPSTR_TEXTCALLBACK)) {
  266.                     Assert(hItem->lpstr == LPSTR_TEXTCALLBACK);
  267.                     hItem->lpstr = NULL;
  268.                     Str_Set(&hItem->lpstr, nm.item.pszText);
  269.                 }
  270.             if (nm.item.mask & TVIF_STATE)
  271.                 hItem->state = lpItem->state;
  272.             if (nm.item.mask & TVIF_IMAGE)
  273.                 hItem->iImage = lpItem->iImage;
  274.             if (nm.item.mask & TVIF_SELECTEDIMAGE)
  275.                 hItem->iSelectedImage = lpItem->iSelectedImage;
  276.             if (nm.item.mask & TVIF_CHILDREN) {
  277.                 switch(nm.item.cChildren) {
  278.                 case I_CHILDRENCALLBACK:
  279.                     hItem->fKids = KIDS_CALLBACK;
  280.                     break;
  281.                 case 0:
  282.                     hItem->fKids = KIDS_FORCE_NO;
  283.                     break;
  284.                 default:
  285.                     hItem->fKids = KIDS_FORCE_YES;
  286.                     break;
  287.                 }
  288.             }
  289.         }
  290.     }
  291. }
  292. // ----------------------------------------------------------------------------
  293. //
  294. //  Draws the given item starting at the given (x,y) and extending down and to
  295. //  the right.
  296. //
  297. // ----------------------------------------------------------------------------
  298. void NEAR TV_DrawItem(PTREE pTree, HTREEITEM hItem, HDC hdc, int x, int y, UINT flags)
  299. {
  300.     int iLevel = hItem->iLevel;
  301.     UINT cxIndent = pTree->cxIndent;
  302.     COLORREF rgbOldBack, rgbOldText;
  303.     RECT rc;
  304.     int iBack, iText;
  305.     LPSTR lpstr;
  306.     int cch;
  307.     UINT etoFlags = ETO_OPAQUE;
  308.     TV_ITEM ti;
  309.     char szTemp[MAX_PATH];
  310.     int iState = 0;
  311.     HFONT hFont; //$BOLD
  312.     rc.top = y;
  313.     rc.bottom = rc.top + pTree->cyItem;
  314.     if (flags & TVDI_ERASE) {
  315. // Opaque the whole item
  316. rc.left = 0;
  317. rc.right = pTree->cxWnd;
  318. FillRect(hdc, &rc, pTree->hbrBk);
  319.     }
  320.     // make sure the callbacks don't invalidate this item
  321.     pTree->hItemPainting = hItem;
  322.     ti.pszText = szTemp;
  323.     ti.cchTextMax  = sizeof(szTemp);
  324.     ti.stateMask = TVIS_OVERLAYMASK | TVIS_CUT | TVIS_BOLD; //$BOLD
  325.     TV_GetItem(pTree, hItem, TVIF_IMAGE | TVIF_STATE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_CHILDREN, &ti);
  326.     pTree->hItemPainting = NULL;
  327.     if (flags & TVDI_NOTREE)
  328. iLevel = 0;
  329.     else if ((pTree->style & (TVS_HASLINES | TVS_HASBUTTONS)) &&
  330.               (pTree->style & TVS_LINESATROOT))
  331. // Make room for the "plus" at the front of the tree
  332. x += cxIndent;
  333.     x += iLevel * cxIndent;
  334.     // draw image
  335.     if (!(flags & TVDI_NOTREE))
  336.     {
  337.         if (pTree->himlState) {
  338.             iState = TV_StateIndex(&ti);
  339.             if (iState) {
  340.                 ImageList_Draw(pTree->himlState, iState, hdc, x,
  341.                                y + (pTree->cyItem - pTree->cyState), ILD_NORMAL);
  342.                 x += pTree->cxState;
  343.             }
  344.         }
  345.         if (pTree->hImageList) {
  346.             UINT fStyle = 0;
  347.             COLORREF rgb = CLR_HILIGHT;
  348.             int i = (ti.state & TVIS_SELECTED) ? ti.iSelectedImage : ti.iImage;
  349.             if (ti.state & TVIS_CUT) {
  350.                 fStyle |= ILD_BLEND50;
  351.                 rgb = ImageList_GetBkColor(pTree->hImageList);
  352.             }
  353.             ImageList_DrawEx(pTree->hImageList, i, hdc,
  354.                            x, y + ((pTree->cyItem - pTree->cyImage) / 2), 0, 0,
  355.                            CLR_DEFAULT, rgb,
  356.                            fStyle | (ti.state & TVIS_OVERLAYMASK));
  357.         }
  358.     }
  359.     if (pTree->hImageList) {
  360.         // even if not drawing image, draw text in right place
  361.         x += pTree->cxImage;
  362.     }
  363.     // draw text
  364.     if ((ti.state & TVIS_DROPHILITED) ||
  365.         (!pTree->hDropTarget && 
  366.          ((ti.state & TVIS_SELECTED) &&
  367.           (pTree->fFocus || (pTree->style & TVS_SHOWSELALWAYS))) &&
  368.          !(flags & TVDI_GRAYCTL))) {
  369. // selected
  370.         iBack = COLOR_HIGHLIGHT;
  371.         iText = COLOR_HIGHLIGHTTEXT;
  372.     } else {
  373. // not selected
  374.         iBack = (flags & TVDI_GRAYCTL) ? COLOR_3DFACE : COLOR_WINDOW;
  375.         iText = ((ti.state & TVIS_DISABLED) || (flags & TVDI_GRAYCTL)) ? COLOR_GRAYTEXT : COLOR_WINDOWTEXT;
  376.     }
  377.     if (iBack)
  378.      rgbOldBack = SetBkColor(hdc, GetSysColor(iBack));
  379.     rgbOldText = SetTextColor(hdc, GetSysColor(iText));
  380.     // if forcing black and transparent, do so.  dc's BkMode should
  381.     // already be set to TRANSPARENT by caller
  382.     if (flags & TVDI_TRANSTEXT)
  383.     {
  384. SetTextColor(hdc, 0x000000);
  385. etoFlags = 0; // don't opaque nothin'
  386.     }
  387.     // Figure out which font to use. //$BOLD
  388.     if (ti.state & TVIS_BOLD) { //$BOLD
  389. hFont = pTree->hFontBold; //$BOLD
  390.     } else { //$BOLD
  391. hFont = pTree->hFont; //$BOLD
  392.     } //$BOLD
  393.     hFont = SelectObject(hdc, hFont); //$BOLD
  394.     lpstr = ti.pszText;
  395.     cch = lstrlen(lpstr);
  396.     if (!hItem->iWidth || (hItem->lpstr == LPSTR_TEXTCALLBACK))
  397.     {
  398. TV_ComputeItemWidth(pTree, hItem, hdc); //$BOLD
  399.     }
  400.     rc.left = x;
  401.     rc.right = x + hItem->iWidth;
  402.     // Draw the text, unless it's the one we are editing
  403.     if (pTree->htiEdit != hItem || !IsWindow(pTree->hwndEdit) || !IsWindowVisible(pTree->hwndEdit))
  404.     {
  405.         ExtTextOut(hdc, x + g_cxLabelMargin, y + ((pTree->cyItem - pTree->cyText) / 2) + g_cyBorder,
  406.                    etoFlags, &rc, lpstr, cch, NULL);
  407.         // Draw the focus rect, if appropriate.
  408.         if (pTree->fFocus && (hItem == pTree->hCaret) && !(flags & (TVDI_TRANSTEXT | TVDI_GRAYCTL)))
  409.             DrawFocusRect(hdc, &rc);
  410.     }
  411.     if (iBack)
  412. SetBkColor(hdc, rgbOldBack);
  413.     SetTextColor(hdc, rgbOldText);
  414.     // Restore the original font. //$BOLD
  415.     SelectObject(hdc, hFont); //$BOLD
  416.     // Notice that we should have opaque'd the rest of the line above if no tree
  417.     if (!(flags & TVDI_NOTREE))
  418.     {
  419. if (pTree->hImageList)
  420.     x -= pTree->cxImage;
  421.         if (iState)
  422.             x -= pTree->cxState;
  423.         if (pTree->style & TVS_HASLINES)
  424. {
  425.             int i;
  426.             x -= cxIndent;
  427.             if (iLevel-- || (pTree->style & TVS_LINESATROOT))
  428.             {
  429. // HACK: Special case the first root
  430. // We will draw a "last" sibling button upside down
  431. if (iLevel == -1 && hItem == hItem->hParent->hKids)
  432. {
  433.                     if (hItem->hNext) {
  434.                         i = 2;
  435.                         if (ti.cChildren && (pTree->style & TVS_HASBUTTONS))
  436.                         {
  437.                             i += 2;
  438.                             if (ti.state & TVIS_EXPANDED)
  439.                                 i += 2;
  440.                         }
  441.                         StretchBlt(hdc, x, y + pTree->cyItem, cxIndent, -pTree->cyItem, pTree->hdcBits, i * cxIndent, 0, cxIndent, pTree->cyItem, SRCCOPY);
  442.                         i = -1;
  443.                     }
  444.                     else
  445.                     {
  446.                         // first root no siblings
  447.                         // if there's no other item, draw just the button if button mode,
  448.                         if (pTree->style & TVS_HASBUTTONS)
  449.                         {
  450.                             if (ti.cChildren) {
  451.                                 // hasbuttons, has lines, lines at root
  452.                                 i = (ti.state & TVIS_EXPANDED) ? 9 : 8;
  453.                             } else {
  454.                                 i = 7;
  455.                             }
  456.                         }
  457.                         else
  458.                         {
  459.                             i = 3;
  460.                         }
  461.                     }
  462.                 }
  463. else
  464. {
  465.     i = (hItem->hNext) ? 1 : 2;
  466.     if (ti.cChildren && (pTree->style & TVS_HASBUTTONS))
  467.     {
  468. i += 2;
  469. if (ti.state & TVIS_EXPANDED)
  470.     i += 2;
  471.     }
  472. }
  473.                 if (i != -1)
  474.                     BitBlt(hdc, x, y, cxIndent, pTree->cyItem, pTree->hdcBits, i * cxIndent, 0, SRCCOPY);
  475. while ((--iLevel >= 0) || ((pTree->style & TVS_LINESATROOT) && iLevel >= -1))
  476. {
  477.     hItem = hItem->hParent;
  478.     x -= cxIndent;
  479.     if (hItem->hNext)
  480. BitBlt(hdc, x, y, cxIndent, pTree->cyItem, pTree->hdcBits, 0, 0, SRCCOPY);
  481. }
  482.     }
  483. }
  484. else
  485. {
  486.             if ((pTree->style & TVS_HASBUTTONS) && (iLevel || pTree->style & TVS_LINESATROOT)
  487.                 && ti.cChildren)
  488.             {
  489. int i = (ti.state & TVIS_EXPANDED) ? cxIndent : 0;
  490. x -= cxIndent;
  491. BitBlt(hdc, x, y, cxIndent, pTree->cyItem, pTree->hdcBits, i, 0, SRCCOPY);
  492.     }
  493. }
  494.     }
  495. }
  496. void NEAR TV_DrawTree(PTREE pTree, HDC hdc, BOOL fErase, LPRECT lprc)
  497. {
  498.     int x, y;
  499.     int iStart, iCnt;
  500.     UINT uFlags;
  501.     RECT rc;
  502.     if (!pTree->fRedraw)
  503.         return;
  504.     x = -pTree->xPos;
  505.     TV_GetBackgroundBrush(pTree, hdc);
  506.     rc = *lprc;
  507.     if ((pTree->cItems == 0) || (!pTree->hTop))
  508. goto ClearAndReturn;
  509.     iStart = lprc->top / pTree->cyItem;
  510.     y = iStart * pTree->cyItem;
  511.     Assert(ITEM_VISIBLE(pTree->hTop));
  512.     iCnt = pTree->cShowing - pTree->hTop->iShownIndex;
  513.     if (iStart < iCnt)
  514.     {
  515.         HTREEITEM   hItem;
  516.         HFONT       hOldFont;
  517.         int         cVisible = min(iCnt, ((lprc->bottom / pTree->cyItem) + 1)) - iStart;
  518.         for (hItem = pTree->hTop; hItem && iStart; iStart--)
  519.             hItem = TV_GetNextVisItem(hItem);
  520.         hOldFont = pTree->hFont ? SelectObject(hdc, pTree->hFont) : NULL;
  521. // TVDI_* for all items
  522. uFlags = (pTree->style & WS_DISABLED) ? TVDI_GRAYCTL : 0;
  523. if (fErase)
  524.     uFlags |= TVDI_ERASE;
  525. // BUGBUG: I've seen this code fault, getting NULL back from
  526. // TV_GetNextVisItem()
  527.         // loop from the first visible item until either all visible items are
  528.         // drawn or there are no more items to draw
  529.         while (cVisible)
  530.         {
  531.             TV_DrawItem(pTree, hItem, hdc, x, y, uFlags);
  532.     y += pTree->cyItem;
  533.             // if there is still room for more visible items, figure out the next
  534.             // item to be drawn
  535.             if (--cVisible)
  536.                 hItem = TV_GetNextVisItem(hItem);
  537. }
  538.         if (hOldFont)
  539.             SelectObject(hdc, hOldFont);
  540. rc.top = y;
  541.     }
  542. ClearAndReturn:
  543.     if (fErase)
  544. // Opaque out everything we have not drawn explicitly
  545. FillRect(hdc, &rc, pTree->hbrBk);
  546. }
  547. // ----------------------------------------------------------------------------
  548. //
  549. //  Set up for paint, call DrawTree, and clean up after paint.
  550. //
  551. // ----------------------------------------------------------------------------
  552. void NEAR TV_Paint(PTREE pTree, HDC hdc)
  553. {
  554.     PAINTSTRUCT ps;
  555.     if (hdc)
  556.     {
  557.         // hdc != 0 indicates a subclassed paint -- use the hdc passed in
  558.         SetRect(&ps.rcPaint, 0, 0, pTree->cxWnd, pTree->cyWnd);
  559.         TV_DrawTree(pTree, hdc, TRUE, &ps.rcPaint);
  560.     }
  561.     else
  562.     {
  563. BeginPaint(pTree->hwnd, &ps);
  564.         TV_DrawTree(pTree, ps.hdc, ps.fErase, &ps.rcPaint);
  565.         EndPaint(pTree->hwnd, &ps);
  566.     }
  567. }
  568. // ----------------------------------------------------------------------------
  569. // Create an imagelist to be used for dragging.
  570. //
  571. // 1) create mask and image bitmap matching the select bounds size
  572. // 2) draw the text to both bitmaps (in black for now)
  573. // 3) create an imagelist with these bitmaps
  574. // 4) make a dithered copy of the image onto the new imagelist
  575. // ----------------------------------------------------------------------------
  576. HIMAGELIST NEAR TV_CreateDragImage(PTREE pTree, HTREEITEM hItem)
  577. {
  578.     HDC hdcMem = NULL;
  579.     HBITMAP hbmImage = NULL;
  580.     HBITMAP hbmMask = NULL;
  581.     HBITMAP hbmOld;
  582.     HIMAGELIST himl = NULL;
  583.     int dx, dy;
  584.     int iSrc;
  585.     TV_ITEM ti;
  586.     // BUGBUG??? we know it's already been drawn, so is iWidth valid???
  587.     dx = hItem->iWidth + pTree->cxImage;
  588.     dy = pTree->cyItem;
  589.     if (!(hdcMem = CreateCompatibleDC(NULL)))
  590. goto CDI_Exit;
  591.     if (!(hbmImage = CreateColorBitmap(dx, dy)))
  592. goto CDI_Exit;
  593.     if (!(hbmMask = CreateMonoBitmap(dx, dy)))
  594. goto CDI_Exit;
  595.     // prepare for drawing the item
  596.     if (pTree->hFont)
  597. SelectObject(hdcMem, pTree->hFont);
  598.     SetBkMode(hdcMem, TRANSPARENT);
  599.     /*
  600.     ** draw the text to both bitmaps
  601.     */
  602.     hbmOld = SelectObject(hdcMem, hbmImage);
  603.     // fill image with black for transparency
  604.     PatBlt(hdcMem, 0, 0, dx, dy, BLACKNESS);
  605.     TV_DrawItem(pTree, hItem, hdcMem, 0, 0,
  606.      TVDI_NOIMAGE | TVDI_NOTREE | TVDI_TRANSTEXT);
  607.     SelectObject(hdcMem, hbmMask);
  608.     // fill mask with white for transparency
  609.     PatBlt(hdcMem, 0, 0, dx, dy, WHITENESS);
  610.     TV_DrawItem(pTree, hItem, hdcMem, 0, 0,
  611.      TVDI_NOIMAGE | TVDI_NOTREE | TVDI_TRANSTEXT);
  612.     // unselect objects that we used
  613.     SelectObject(hdcMem, hbmOld);
  614.     SelectObject(hdcMem, g_hfontSystem);
  615.     /*
  616.     ** make an image list that for now only has the text
  617.     */
  618.     //
  619.     // BUGBUG: To fix a pri-1 M7 bug, we create a shared image list.
  620.     //
  621.     if (!(himl = ImageList_Create(dx, dy, ILC_MASK, 1, 0)))
  622. goto CDI_Exit;
  623.     ImageList_SetBkColor(himl, CLR_NONE);
  624.     ImageList_Add(himl, hbmImage, hbmMask);
  625.     /*
  626.     ** make a dithered copy of the image part onto our bitmaps
  627.     ** (need both bitmap and mask to be dithered)
  628.     */
  629.     TV_GetItem(pTree, hItem, TVIF_IMAGE, &ti);
  630.     iSrc = ti.iImage;
  631.     ImageList_CopyDitherImage(himl, 0, 0, (pTree->cyItem - pTree->cyImage) / 2,
  632.      pTree->hImageList, iSrc, hItem->state & TVIS_OVERLAYMASK);
  633. CDI_Exit:
  634.     if (hdcMem)
  635. DeleteObject(hdcMem);
  636.     if (hbmImage)
  637. DeleteObject(hbmImage);
  638.     if (hbmMask)
  639. DeleteObject(hbmMask);
  640.     return himl;
  641. }