Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1456 lines
45 KiB

  1. #include "ctlspriv.h"
  2. #include "treeview.h"
  3. #include "image.h"
  4. extern void TruncateString(char *sz, int cch);
  5. void TV_GetBackgroundBrush(PTREE pTree, HDC hdc)
  6. {
  7. if (pTree->clrBk == (COLORREF)-1)
  8. {
  9. if (pTree->ci.style & WS_DISABLED)
  10. pTree->hbrBk = FORWARD_WM_CTLCOLORSTATIC(pTree->ci.hwndParent, hdc, pTree->ci.hwnd, SendMessage);
  11. else
  12. pTree->hbrBk = FORWARD_WM_CTLCOLOREDIT(pTree->ci.hwndParent, hdc, pTree->ci.hwnd, SendMessage);
  13. }
  14. }
  15. // ----------------------------------------------------------------------------
  16. //
  17. // Draws a horizontal or vertical dotted line from the given (x,y) location
  18. // for the given length (c).
  19. //
  20. // ----------------------------------------------------------------------------
  21. void TV_DrawDottedLine(HDC hdc, int x, int y, int c, BOOL fVert)
  22. {
  23. while (c > 0)
  24. {
  25. PatBlt(hdc, x, y, 1, 1, PATCOPY);
  26. if (fVert)
  27. y += 2;
  28. else
  29. x += 2;
  30. c -= 2;
  31. }
  32. }
  33. // ----------------------------------------------------------------------------
  34. //
  35. // Draws a plus or minus sign centered around the given (x,y) location and
  36. // extending out from that location the given distance (c).
  37. //
  38. // ----------------------------------------------------------------------------
  39. // TV_DrawPlusMinus is theme aware
  40. void TV_DrawPlusMinus(PTREE pTree, HDC hdc, int x, int y, int c, HBRUSH hbrSign, HBRUSH hbrBox, HBRUSH hbrBk, BOOL fPlus)
  41. {
  42. HRESULT hr = E_FAIL;
  43. int n;
  44. int p = (c * 7) / 10;
  45. n = p * 2 + 1;
  46. if (pTree->hTheme)
  47. {
  48. RECT rc = { x - c, y - c, x + c + 1, y + c + 1 };
  49. hr = DrawThemeBackground(pTree->hTheme, hdc, TVP_GLYPH, fPlus ? GLPS_CLOSED : GLPS_OPENED, &rc, 0);
  50. }
  51. if (FAILED(hr))
  52. {
  53. SelectObject(hdc, hbrBk);
  54. PatBlt(hdc, x - c, y - c, 2*c, 2*c, PATCOPY);
  55. SelectObject(hdc, hbrSign);
  56. if (p >= 5)
  57. {
  58. PatBlt(hdc, x - p, y - 1, n, 3, PATCOPY);
  59. if (fPlus)
  60. PatBlt(hdc, x - 1, y - p, 3, n, PATCOPY);
  61. p--;
  62. n -= 2;
  63. }
  64. PatBlt(hdc, x - p, y, n, 1, PATCOPY);
  65. if (fPlus)
  66. PatBlt(hdc, x, y - p, 1, n, PATCOPY);
  67. n = c * 2 + 1;
  68. SelectObject(hdc, hbrBox);
  69. PatBlt(hdc, x - c, y - c, n, 1, PATCOPY);
  70. PatBlt(hdc, x - c, y - c, 1, n, PATCOPY);
  71. PatBlt(hdc, x - c, y + c, n, 1, PATCOPY);
  72. PatBlt(hdc, x + c, y - c, 1, n, PATCOPY);
  73. }
  74. }
  75. // ----------------------------------------------------------------------------
  76. //
  77. // Create the bitmaps for the indent area of the tree as follows
  78. // if fHasLines && fHasButtons --> 7 bitmaps
  79. // if fHasLines && !fHasButtons --> 3 bitmaps
  80. // if !fHasLines && fHasButtons --> 2 bitmaps
  81. //
  82. // sets hStartBmp, hBmp, hdcBits
  83. //
  84. // If "has lines" then there are three basic bitmaps.
  85. //
  86. // | | |
  87. // | +--- +---
  88. // | |
  89. //
  90. // (The plan vertical line does not get buttons.)
  91. //
  92. // Otherwise, there are no lines, so the basic bitmaps are blank.
  93. //
  94. // If "has buttons", then the basic bitmaps are augmented with buttons.
  95. //
  96. // [+] [-]
  97. //
  98. // And if you have "lines at root", you get
  99. //
  100. // __
  101. //
  102. //
  103. // And if you have "lines at root" with "has buttons", then you also get
  104. //
  105. // --[+] --[-]
  106. //
  107. // So, there are twelve image types. Here they are, with the code names
  108. // written underneath.
  109. //
  110. // | | | | | | |
  111. // | +--- +--- [+]-- [+]-- [-]-- [-]--
  112. // | | | |
  113. //
  114. // "|" "|-" "L" "|-+" "L+" "|--" "L-"
  115. //
  116. // --- [+]-- [-]-- [+] [-]
  117. //
  118. // ".-" ".-+" ".--" "+" "-"
  119. //
  120. // And the master table of which styles get which images.
  121. //
  122. //
  123. // LINES BTNS ROOT | |- L |-+ L+ |-- L- .- .-+ .-- + -
  124. //
  125. // x 0 1
  126. // x 0 1 2 3
  127. // x 0 1 2 3
  128. // x x 0 1 2 3 4 5 6
  129. // x x 0 1 2 3
  130. // x x x 0 1 2 3 4 5 6 7 8 9
  131. //
  132. // ----------------------------------------------------------------------------
  133. void TV_DrawV(PTREE pTree, HDC hdc, int x, int y) // "|"
  134. {
  135. int xMid;
  136. HBRUSH hbrOld = SelectObject(hdc, pTree->hbrLine);
  137. if (pTree->hImageList)
  138. xMid = (pTree->cxImage - MAGIC_INDENT) / 2;
  139. else
  140. xMid = pTree->cxIndent / 2;
  141. TV_DrawDottedLine(hdc, x + xMid, y, pTree->cyItem, TRUE);
  142. SelectObject(hdc, hbrOld);
  143. }
  144. void TV_DrawT(PTREE pTree, HDC hdc, int x, int y) // "|-"
  145. {
  146. int xMid, yMid;
  147. HBRUSH hbrOld = SelectObject(hdc, pTree->hbrLine);
  148. if (pTree->hImageList)
  149. xMid = (pTree->cxImage - MAGIC_INDENT) / 2;
  150. else
  151. xMid = pTree->cxIndent / 2;
  152. yMid = ((pTree->cyItem / 2) + 1) & ~1;
  153. TV_DrawDottedLine(hdc, x + xMid, y, pTree->cyItem, TRUE);
  154. TV_DrawDottedLine(hdc, x + xMid, y + yMid, pTree->cxIndent - xMid, FALSE);
  155. SelectObject(hdc, hbrOld);
  156. }
  157. void TV_DrawL(PTREE pTree, HDC hdc, int x, int y, BOOL bRoot) // "L"
  158. {
  159. int xMid, yMid;
  160. HBRUSH hbrOld = SelectObject(hdc, pTree->hbrLine);
  161. if (pTree->hImageList)
  162. xMid = (pTree->cxImage - MAGIC_INDENT) / 2;
  163. else
  164. xMid = pTree->cxIndent / 2;
  165. yMid = ((pTree->cyItem / 2) + 1) & ~1;
  166. if (!bRoot)
  167. {
  168. TV_DrawDottedLine(hdc, x + xMid, y, yMid, TRUE);
  169. } else
  170. {
  171. TV_DrawDottedLine(hdc, x + xMid, y + yMid, yMid, TRUE);
  172. }
  173. TV_DrawDottedLine(hdc, x + xMid, y + yMid, pTree->cxIndent - xMid, FALSE);
  174. SelectObject(hdc, hbrOld);
  175. }
  176. void TV_DrawPML(PTREE pTree, HDC hdc, int x, int y, BOOL fPlus, BOOL fL, BOOL bRoot)
  177. {
  178. int xMid, yMid, c;
  179. HBRUSH hbrOld = SelectObject(hdc, pTree->hbrLine);
  180. if (pTree->hImageList)
  181. xMid = (pTree->cxImage - MAGIC_INDENT) / 2;
  182. else
  183. xMid = pTree->cxIndent / 2;
  184. yMid = ((pTree->cyItem / 2) + 1) & ~1;
  185. c = (min(xMid, yMid)) / 2;
  186. if (fL)
  187. {
  188. if (!bRoot)
  189. {
  190. TV_DrawDottedLine(hdc, x + xMid, y, yMid - c, TRUE);
  191. } else
  192. {
  193. TV_DrawDottedLine(hdc, x + xMid, y + yMid + c, yMid - c, TRUE);
  194. }
  195. TV_DrawDottedLine(hdc, x + xMid + c, y + yMid, pTree->cxIndent - xMid - c, FALSE);
  196. }
  197. else
  198. {
  199. TV_DrawDottedLine(hdc, x + xMid, y, yMid - c, TRUE);
  200. TV_DrawDottedLine(hdc, x + xMid + c, y + yMid, pTree->cxIndent - xMid - c, FALSE);
  201. TV_DrawDottedLine(hdc, x + xMid, y + yMid + c, yMid - c, TRUE);
  202. }
  203. TV_DrawPlusMinus(pTree, hdc, x + xMid, y + yMid, c, pTree->hbrText, pTree->hbrLine, pTree->hbrBk, fPlus);
  204. SelectObject(hdc, hbrOld);
  205. }
  206. void TV_DrawTP(PTREE pTree, HDC hdc, int x, int y) // "|-+"
  207. {
  208. TV_DrawPML(pTree, hdc, x, y, TRUE, FALSE, FALSE);
  209. }
  210. void TV_DrawLP(PTREE pTree, HDC hdc, int x, int y, BOOL bRoot) // "L+"
  211. {
  212. TV_DrawPML(pTree, hdc, x, y, TRUE, TRUE, bRoot);
  213. }
  214. void TV_DrawTM(PTREE pTree, HDC hdc, int x, int y) // "|--"
  215. {
  216. TV_DrawPML(pTree, hdc, x, y, FALSE, FALSE, FALSE);
  217. }
  218. void TV_DrawLM(PTREE pTree, HDC hdc, int x, int y, BOOL bRoot) // "L-"
  219. {
  220. TV_DrawPML(pTree, hdc, x, y, FALSE, TRUE, bRoot);
  221. }
  222. void TV_DrawH(PTREE pTree, HDC hdc, int x, int y) // ".-"
  223. {
  224. int xMid, yMid;
  225. HBRUSH hbrOld = SelectObject(hdc, pTree->hbrLine);
  226. if (pTree->hImageList)
  227. xMid = (pTree->cxImage - MAGIC_INDENT) / 2;
  228. else
  229. xMid = pTree->cxIndent / 2;
  230. yMid = ((pTree->cyItem / 2) + 1) & ~1;
  231. TV_DrawDottedLine(hdc, x + xMid, y + yMid, pTree->cxIndent - xMid, FALSE);
  232. SelectObject(hdc, hbrOld);
  233. }
  234. void TV_DrawHP(PTREE pTree, HDC hdc, int x, int y) // ".-+"
  235. {
  236. int xMid, yMid, c;
  237. HBRUSH hbrOld = SelectObject(hdc, pTree->hbrLine);
  238. if (pTree->hImageList)
  239. xMid = (pTree->cxImage - MAGIC_INDENT) / 2;
  240. else
  241. xMid = pTree->cxIndent / 2;
  242. yMid = ((pTree->cyItem / 2) + 1) & ~1;
  243. c = (min(xMid, yMid)) / 2;
  244. TV_DrawDottedLine(hdc, x + c, y + yMid, pTree->cxIndent - xMid - c, FALSE);
  245. TV_DrawPlusMinus(pTree, hdc, x + xMid, y + yMid, c, pTree->hbrText, pTree->hbrLine, pTree->hbrBk, TRUE);
  246. SelectObject(hdc, hbrOld);
  247. }
  248. void TV_DrawHM(PTREE pTree, HDC hdc, int x, int y) // ".--"
  249. {
  250. int xMid, yMid, c;
  251. HBRUSH hbrOld = SelectObject(hdc, pTree->hbrLine);
  252. if (pTree->hImageList)
  253. xMid = (pTree->cxImage - MAGIC_INDENT) / 2;
  254. else
  255. xMid = pTree->cxIndent / 2;
  256. yMid = ((pTree->cyItem / 2) + 1) & ~1;
  257. c = (min(xMid, yMid)) / 2;
  258. TV_DrawDottedLine(hdc, x + c, y + yMid, pTree->cxIndent - xMid - c, FALSE);
  259. TV_DrawPlusMinus(pTree, hdc, x + xMid, y + yMid, c, pTree->hbrText, pTree->hbrLine, pTree->hbrBk, FALSE);
  260. SelectObject(hdc, hbrOld);
  261. }
  262. void TV_DrawP(PTREE pTree, HDC hdc, int x, int y) // "+"
  263. {
  264. int xMid, yMid, c;
  265. if (pTree->hImageList)
  266. xMid = (pTree->cxImage - MAGIC_INDENT) / 2;
  267. else
  268. xMid = pTree->cxIndent / 2;
  269. yMid = ((pTree->cyItem / 2) + 1) & ~1;
  270. c = (min(xMid, yMid)) / 2;
  271. TV_DrawPlusMinus(pTree, hdc, x + xMid, y + yMid, c, pTree->hbrText, pTree->hbrLine, pTree->hbrBk, TRUE);
  272. }
  273. void TV_DrawM(PTREE pTree, HDC hdc, int x, int y) // "-"
  274. {
  275. int xMid, yMid, c;
  276. if (pTree->hImageList)
  277. xMid = (pTree->cxImage - MAGIC_INDENT) / 2;
  278. else
  279. xMid = pTree->cxIndent / 2;
  280. yMid = ((pTree->cyItem / 2) + 1) & ~1;
  281. c = (min(xMid, yMid)) / 2;
  282. TV_DrawPlusMinus(pTree, hdc, x + xMid, y + yMid, c, pTree->hbrText, pTree->hbrLine, pTree->hbrBk, FALSE);
  283. }
  284. void TV_DrawState2(PTREE pTree, int iState, HDC hdc, int x, int y, BOOL bRoot)
  285. {
  286. switch (iState)
  287. {
  288. case 0:
  289. if (pTree->ci.style & TVS_HASLINES)
  290. {
  291. TV_DrawV(pTree, hdc, x, y);
  292. }
  293. else
  294. {
  295. TV_DrawP(pTree, hdc, x, y);
  296. }
  297. break;
  298. case 1:
  299. if (pTree->ci.style & TVS_HASLINES)
  300. {
  301. TV_DrawT(pTree, hdc, x, y);
  302. }
  303. else
  304. {
  305. TV_DrawM(pTree, hdc, x, y);
  306. }
  307. break;
  308. case 2:
  309. TV_DrawL(pTree, hdc, x, y, bRoot);
  310. break;
  311. case 3:
  312. if (!(pTree->ci.style & TVS_HASBUTTONS))
  313. {
  314. TV_DrawH(pTree, hdc, x, y);
  315. }
  316. else
  317. {
  318. TV_DrawTP(pTree, hdc, x, y);
  319. }
  320. break;
  321. case 4:
  322. TV_DrawLP(pTree, hdc, x, y, bRoot);
  323. break;
  324. case 5:
  325. TV_DrawTM(pTree, hdc, x, y);
  326. break;
  327. case 6:
  328. TV_DrawLM(pTree, hdc, x, y, bRoot);
  329. break;
  330. case 7:
  331. TV_DrawH(pTree, hdc, x, y);
  332. break;
  333. case 8:
  334. TV_DrawHP(pTree, hdc, x, y);
  335. break;
  336. case 9:
  337. TV_DrawHM(pTree, hdc, x, y);
  338. break;
  339. }
  340. }
  341. void TV_DrawState(PTREE pTree, int iState, HDC hdc, int x, int y)
  342. {
  343. TV_DrawState2(pTree, iState, hdc, x, y, FALSE);
  344. }
  345. // TV_CreateIndentBmps is theme aware
  346. void TV_CreateIndentBmps(PTREE pTree)
  347. {
  348. if (pTree->fRedraw)
  349. InvalidateRect(pTree->ci.hwnd, NULL, TRUE);
  350. return;
  351. }
  352. // ----------------------------------------------------------------------------
  353. //
  354. // fills in a TVITEM structure based by coying data from the item or
  355. // by calling the callback to get it.
  356. //
  357. // in:
  358. // hItem item to get TVITEM struct for
  359. // mask which bits of the TVITEM struct you want (TVIF_ flags)
  360. // out:
  361. // lpItem TVITEM filled in
  362. //
  363. // ----------------------------------------------------------------------------
  364. void TV_GetItem(PTREE pTree, HTREEITEM hItem, UINT mask, LPTVITEMEX lpItem)
  365. {
  366. TV_DISPINFO nm;
  367. if (!hItem || !lpItem)
  368. return;
  369. DBG_ValidateTreeItem(hItem, FALSE);
  370. nm.item.mask = 0;
  371. // We need to check the mask to see if lpItem->pszText is valid
  372. // And even then, it might not be, so be paranoid
  373. if ((mask & TVIF_TEXT) && lpItem->pszText && lpItem->cchTextMax)
  374. {
  375. if (hItem->lpstr == LPSTR_TEXTCALLBACK)
  376. {
  377. nm.item.mask |= TVIF_TEXT;
  378. // caller had to fill in pszText and cchTextMax with valid data
  379. nm.item.pszText = lpItem->pszText;
  380. nm.item.cchTextMax = lpItem->cchTextMax;
  381. nm.item.pszText[0] = 0;
  382. #ifdef DEBUG
  383. pTree->fInTextCallback = TRUE;
  384. #endif
  385. }
  386. else
  387. {
  388. ASSERT(hItem->lpstr);
  389. // we could do this but this is dangerous (when responding
  390. // to TVM_GETITEM we would be giving the app a pointer to our data)
  391. // lpItem->pszText = hItem->lpstr;
  392. StringCchCopy(lpItem->pszText, lpItem->cchTextMax, hItem->lpstr);
  393. }
  394. }
  395. if (mask & TVIF_IMAGE)
  396. {
  397. if (hItem->iImage == (WORD)I_IMAGECALLBACK)
  398. nm.item.mask |= TVIF_IMAGE;
  399. else
  400. lpItem->iImage = hItem->iImage;
  401. }
  402. if (mask & TVIF_SELECTEDIMAGE)
  403. {
  404. if (hItem->iSelectedImage == (WORD)I_IMAGECALLBACK)
  405. nm.item.mask |= TVIF_SELECTEDIMAGE;
  406. else
  407. lpItem->iSelectedImage = hItem->iSelectedImage;
  408. }
  409. if (mask & TVIF_INTEGRAL)
  410. {
  411. lpItem->iIntegral = hItem->iIntegral;
  412. }
  413. if (mask & TVIF_CHILDREN)
  414. {
  415. switch (hItem->fKids)
  416. {
  417. case KIDS_COMPUTE:
  418. lpItem->cChildren = hItem->hKids ? 1 : 0;// the actual count doesn't matter
  419. break;
  420. case KIDS_FORCE_YES:
  421. lpItem->cChildren = 1;// the actual count doesn't matter
  422. break;
  423. case KIDS_FORCE_NO:
  424. lpItem->cChildren = 0;
  425. break;
  426. case KIDS_CALLBACK:
  427. nm.item.mask |= TVIF_CHILDREN;
  428. break;
  429. }
  430. }
  431. // copy out constant parameters (and prepare for callback)
  432. // IE4 and IE5.0 did this unconditionally
  433. lpItem->state = nm.item.state = hItem->state;
  434. //
  435. // NOTICE! We do not set TVIF_STATE nm.item.mask and we do not
  436. // check for TVIF_STATE in the "any items need to be filled in
  437. // by callback?" test a few lines below. This is necessary for
  438. // backwards compat. IE5 and earlier did not call the app back
  439. // if the only thing you asked for was TVIF_STATE. You can't
  440. // change this behavior unless you guard it with a version check, or
  441. // apps will break. (They'll get callbacks when they didn't used to.)
  442. // Besides, nobody knows that they can customize the state, so it's
  443. // not like we're missing out on anything.
  444. //
  445. lpItem->lParam = nm.item.lParam = hItem->lParam;
  446. // any items need to be filled in by callback?
  447. if (nm.item.mask & (TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN))
  448. {
  449. nm.item.hItem = hItem;
  450. CCSendNotify(&pTree->ci, TVN_GETDISPINFO, &nm.hdr);
  451. #ifdef DEBUG
  452. pTree->fInTextCallback = FALSE;
  453. #endif
  454. // copy out things that may have been filled in on the callback
  455. if (nm.item.mask & TVIF_CHILDREN)
  456. lpItem->cChildren = nm.item.cChildren;
  457. if (nm.item.mask & TVIF_IMAGE)
  458. lpItem->iImage = nm.item.iImage;
  459. if (nm.item.mask & TVIF_SELECTEDIMAGE)
  460. lpItem->iSelectedImage = nm.item.iSelectedImage;
  461. // callback may have redirected pszText to point into its own buffer
  462. if (nm.item.mask & TVIF_TEXT)
  463. lpItem->pszText = CCReturnDispInfoText(nm.item.pszText, lpItem->pszText, lpItem->cchTextMax);
  464. if (nm.item.mask & TVIF_STATE)
  465. {
  466. lpItem->state = (nm.item.state & nm.item.stateMask) | (lpItem->state & ~nm.item.stateMask);
  467. if ((lpItem->state & TVIS_BOLD) && !pTree->hFontBold)
  468. TV_CreateBoldFont(pTree);
  469. }
  470. if (nm.item.mask & TVIF_DI_SETITEM)
  471. {
  472. if (nm.item.mask & TVIF_TEXT)
  473. if (nm.item.pszText)
  474. {
  475. Str_Set(&hItem->lpstr, nm.item.pszText);
  476. }
  477. if (nm.item.mask & TVIF_STATE)
  478. {
  479. // if the bold bit changed, then the width changed
  480. if ((hItem->state ^ lpItem->state) & TVIS_BOLD)
  481. hItem->iWidth = 0;
  482. hItem->state = (WORD) lpItem->state;
  483. }
  484. if (nm.item.mask & TVIF_IMAGE)
  485. hItem->iImage = (WORD) lpItem->iImage;
  486. if (nm.item.mask & TVIF_SELECTEDIMAGE)
  487. hItem->iSelectedImage = (WORD) lpItem->iSelectedImage;
  488. if (nm.item.mask & TVIF_CHILDREN)
  489. {
  490. switch(nm.item.cChildren)
  491. {
  492. case I_CHILDRENCALLBACK:
  493. hItem->fKids = KIDS_CALLBACK;
  494. break;
  495. case I_CHILDRENAUTO:
  496. hItem->fKids = KIDS_COMPUTE;
  497. break;
  498. case 0:
  499. hItem->fKids = KIDS_FORCE_NO;
  500. break;
  501. default:
  502. hItem->fKids = KIDS_FORCE_YES;
  503. break;
  504. }
  505. }
  506. }
  507. }
  508. }
  509. // ----------------------------------------------------------------------------
  510. //
  511. // Draws the given item starting at the given (x,y) and extending down and to
  512. // the right.
  513. //
  514. // ----------------------------------------------------------------------------
  515. BOOL TV_ShouldItemDrawBlue(PTREE pTree, TVITEMEX *ti, UINT flags)
  516. {
  517. return ( (ti->state & TVIS_DROPHILITED) ||
  518. (!pTree->hDropTarget &&
  519. !(flags & TVDI_GRAYCTL) &&
  520. (ti->state & TVIS_SELECTED) &&
  521. pTree->fFocus));
  522. }
  523. #define TV_ShouldItemDrawDisabled(pTree, pti, flags) (flags & TVDI_GRAYCTL)
  524. //
  525. // Caution: Depending on the user's color scheme, a Gray item may
  526. // end up looking Blue if Gray would otherwise be invisible. So make
  527. // sure that there are other cues that the user can use to tell whether
  528. // the item is "Really Blue" or "Gray masquerading as Blue".
  529. //
  530. // For example, you might get both is if the treeview is
  531. // participating in drag/drop while it is not the active window,
  532. // because the selected item gets "Gray masquerading as Blue" and
  533. // the drop target gets "Really Blue". But we special-case that
  534. // and turn off the selection while we are worrying about drag/drop,
  535. // so there is no confusion after all.
  536. //
  537. BOOL TV_ShouldItemDrawGray(PTREE pTree, TVITEMEX *pti, UINT flags)
  538. {
  539. return ((flags & TVDI_GRAYCTL) ||
  540. (!pTree->hDropTarget &&
  541. ((pti->state & TVIS_SELECTED) &&
  542. (!pTree->fFocus && (pTree->ci.style & TVS_SHOWSELALWAYS)) )));
  543. }
  544. //
  545. // Draw a descender line for the item. It is the caller's job to
  546. // draw the appropriate glyph at level 0.
  547. //
  548. void
  549. TV_DrawDescender(PTREE pTree, HDC hdc, int x, int y, HTREEITEM hItem)
  550. {
  551. int i;
  552. for (i = 1; i < hItem->iIntegral; i++)
  553. {
  554. BitBlt(hdc, x, y + i * pTree->cyItem, pTree->cxIndent, pTree->cyItem, pTree->hdcBits, 0, 0, SRCCOPY);
  555. }
  556. }
  557. //
  558. // Erase any previous descender line for the item.
  559. //
  560. void
  561. TV_EraseDescender(PTREE pTree, HDC hdc, int x, int y, HTREEITEM hItem)
  562. {
  563. RECT rc;
  564. rc.left = x;
  565. rc.right = x + pTree->cxIndent;
  566. rc.top = y + pTree->cyItem;
  567. rc.bottom = y + hItem->iIntegral * pTree->cyItem;
  568. FillRect(hdc, &rc, pTree->hbrBk);
  569. }
  570. //
  571. // Draw (or erase) descenders for siblings and children.
  572. //
  573. void TV_DrawKinDescender(PTREE pTree, HDC hdc, int x, int y, HTREEITEM hItem, UINT state)
  574. {
  575. if (hItem->hNext) // Connect to next sibling
  576. TV_DrawDescender(pTree, hdc, x, y, hItem);
  577. else
  578. TV_EraseDescender(pTree, hdc, x, y, hItem);
  579. // If any bonus images, then need to connect the image to the kids.
  580. if (pTree->himlState || pTree->hImageList) {
  581. if (state & (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) // Connect to expanded kids
  582. TV_DrawDescender(pTree, hdc, x + pTree->cxIndent, y, hItem);
  583. else
  584. TV_EraseDescender(pTree, hdc, x + pTree->cxIndent, y, hItem);
  585. }
  586. }
  587. // TV_DrawItem is theme aware
  588. void TV_DrawItem(PTREE pTree, HTREEITEM hItem, HDC hdc, int x, int y, UINT flags)
  589. {
  590. UINT cxIndent = pTree->cxIndent;
  591. COLORREF rgbOldBack = 0, rgbOldText;
  592. COLORREF clrBk = CLR_DEFAULT;
  593. RECT rc;
  594. int iBack, iText;
  595. HTREEITEM hItemSave = hItem;
  596. LPTSTR lpstr;
  597. int cch;
  598. UINT etoFlags = ETO_OPAQUE | ETO_CLIPPED;
  599. TVITEMEX ti;
  600. TCHAR szTemp[MAX_PATH];
  601. int iState = 0;
  602. HFONT hFont; //$BOLD
  603. DWORD dwRet;
  604. NMTVCUSTOMDRAW nmcd;
  605. BOOL fItemFocused = ((pTree->fFocus) && (hItem == pTree->hCaret));
  606. DWORD clrTextTemp, clrTextBkTemp;
  607. BOOL fSelectedIcon = FALSE;
  608. int iOldBkMode = GetBkMode(hdc);
  609. rc.top = y;
  610. rc.bottom = rc.top + (pTree->cyItem * hItem->iIntegral);
  611. rc.left = 0;
  612. rc.right = pTree->cxWnd;
  613. if (flags & TVDI_ERASE)
  614. {
  615. // Opaque the whole item
  616. FillRect(hdc, &rc, pTree->hbrBk);
  617. }
  618. // make sure the callbacks don't invalidate this item
  619. pTree->hItemPainting = hItem;
  620. ti.pszText = szTemp;
  621. ti.cchTextMax = ARRAYSIZE(szTemp);
  622. ti.stateMask = TVIS_OVERLAYMASK | TVIS_CUT | TVIS_BOLD; //$BOLD
  623. TV_GetItem(pTree, hItem, TVIF_IMAGE | TVIF_STATE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_CHILDREN | TVIF_PARAM, &ti);
  624. pTree->hItemPainting = NULL;
  625. ////////////////
  626. // set up the HDC
  627. if (TV_ShouldItemDrawBlue(pTree,&ti,flags))
  628. {
  629. // selected
  630. iBack = COLOR_HIGHLIGHT;
  631. iText = COLOR_HIGHLIGHTTEXT;
  632. }
  633. else if (TV_ShouldItemDrawDisabled(pTree, &pti, flags))
  634. {
  635. iBack = COLOR_3DFACE;
  636. iText = COLOR_GRAYTEXT;
  637. SetBkMode(hdc, TRANSPARENT);
  638. etoFlags &= ~ ETO_OPAQUE;
  639. }
  640. else if (TV_ShouldItemDrawGray(pTree, &ti, flags))
  641. {
  642. // On some color schemes, the BTNFACE color equals the WINDOW color,
  643. // and our gray comes out invisible. In such case, change from gray
  644. // to blue so you can see it at all.
  645. if (GetSysColor(COLOR_WINDOW) != GetSysColor(COLOR_BTNFACE))
  646. {
  647. iBack = COLOR_BTNFACE;
  648. iText = COLOR_BTNTEXT;
  649. }
  650. else
  651. {
  652. iBack = COLOR_HIGHLIGHT;
  653. iText = COLOR_HIGHLIGHTTEXT;
  654. }
  655. }
  656. else
  657. {
  658. // not selected
  659. iBack = COLOR_WINDOW;
  660. iText = COLOR_WINDOWTEXT;
  661. if (hItem == pTree->hHot)
  662. {
  663. iText = COLOR_HOTLIGHT;
  664. }
  665. }
  666. if (iBack == COLOR_WINDOW && (pTree->clrBk != (COLORREF)-1))
  667. nmcd.clrTextBk = clrTextBkTemp = pTree->clrBk;
  668. else
  669. nmcd.clrTextBk = clrTextBkTemp = GetSysColor(iBack);
  670. if (iText == COLOR_WINDOWTEXT && (pTree->clrText != (COLORREF)-1))
  671. nmcd.clrText = clrTextTemp = pTree->clrText;
  672. else
  673. nmcd.clrText = clrTextTemp = GetSysColor(iText);
  674. // if forcing black and transparent, do so. dc's BkMode should
  675. // already be set to TRANSPARENT by caller
  676. if (flags & TVDI_TRANSTEXT)
  677. {
  678. nmcd.clrText = clrTextTemp = 0x000000;
  679. etoFlags = 0; // don't opaque nothin'
  680. }
  681. rgbOldBack = SetBkColor(hdc, nmcd.clrTextBk);
  682. rgbOldText = SetTextColor(hdc, nmcd.clrText);
  683. if (pTree->ci.style & TVS_RTLREADING)
  684. etoFlags |= ETO_RTLREADING;
  685. // Figure out which font to use.
  686. if (ti.state & TVIS_BOLD)
  687. {
  688. hFont = pTree->hFontBold;
  689. if (hItem == pTree->hHot)
  690. {
  691. hFont = CCGetHotFont(pTree->hFontBold, &pTree->hFontBoldHot);
  692. }
  693. }
  694. else
  695. {
  696. hFont = pTree->hFont;
  697. if (hItem == pTree->hHot)
  698. {
  699. hFont = CCGetHotFont(pTree->hFont, &pTree->hFontHot);
  700. }
  701. }
  702. hFont = SelectObject(hdc, hFont);
  703. // End HDC setup
  704. ////////////////
  705. // notify on custom draw then do it!
  706. nmcd.nmcd.hdc = hdc;
  707. nmcd.nmcd.dwItemSpec = (DWORD_PTR)hItem;
  708. nmcd.nmcd.uItemState = 0;
  709. nmcd.nmcd.rc = rc;
  710. if (flags & TVDI_NOTREE)
  711. nmcd.iLevel = 0;
  712. else
  713. nmcd.iLevel = hItem->iLevel;
  714. if (ti.state & TVIS_SELECTED)
  715. {
  716. fSelectedIcon = TRUE;
  717. if (pTree->fFocus || (pTree->ci.style & TVS_SHOWSELALWAYS))
  718. nmcd.nmcd.uItemState |= CDIS_SELECTED;
  719. }
  720. if (fItemFocused)
  721. nmcd.nmcd.uItemState |= CDIS_FOCUS;
  722. if (hItem == pTree->hHot)
  723. nmcd.nmcd.uItemState |= CDIS_HOT;
  724. nmcd.nmcd.lItemlParam = ti.lParam;
  725. dwRet = CICustomDrawNotify(&pTree->ci, CDDS_ITEMPREPAINT, &nmcd.nmcd);
  726. if (dwRet & CDRF_SKIPDEFAULT)
  727. return;
  728. fItemFocused = (nmcd.nmcd.uItemState & CDIS_FOCUS);
  729. if (nmcd.nmcd.uItemState & CDIS_SELECTED)
  730. ti.state |= TVIS_SELECTED;
  731. else
  732. {
  733. ti.state &= ~TVIS_SELECTED;
  734. }
  735. if (nmcd.clrTextBk != clrTextBkTemp)
  736. SetBkColor(hdc, nmcd.clrTextBk);
  737. if (nmcd.clrText != clrTextTemp)
  738. SetTextColor(hdc, nmcd.clrText);
  739. if (pTree->ci.style & TVS_FULLROWSELECT &&
  740. !(flags & TVDI_TRANSTEXT))
  741. {
  742. FillRectClr(hdc, &nmcd.nmcd.rc, GetBkColor(hdc));
  743. etoFlags |= ETO_OPAQUE;
  744. clrBk = CLR_NONE;
  745. }
  746. if (!(flags & TVDI_NOTREE))
  747. {
  748. if ((pTree->ci.style & (TVS_HASLINES | TVS_HASBUTTONS)) &&
  749. (pTree->ci.style & TVS_LINESATROOT))
  750. // Make room for the "plus" at the front of the tree
  751. x += cxIndent;
  752. }
  753. // deal with margin, etc.
  754. x += (pTree->cxBorder + (nmcd.iLevel * cxIndent));
  755. y += pTree->cyBorder;
  756. // draw image
  757. if ((!(flags & TVDI_NOTREE) && !(dwRet & TVCDRF_NOIMAGES)) || (flags & TVDI_FORCEIMAGE))
  758. {
  759. int dx, dy; // to clip the images within the borders.
  760. COLORREF clrImage = CLR_HILIGHT;
  761. COLORREF clrBkImage = clrBk;
  762. if (flags & TVDI_NOBK)
  763. {
  764. clrBkImage = CLR_NONE;
  765. }
  766. if (pTree->himlState)
  767. {
  768. iState = TV_StateIndex(&ti);
  769. // go figure. in the treeview, 0 for the state image index
  770. // means draw nothing... the 0th item is unused.
  771. // the listview is 0 based and uses the 0th item.
  772. if (iState)
  773. {
  774. dx = min(pTree->cxState, pTree->cxMax - pTree->cxBorder - x);
  775. dy = min(pTree->cyState, pTree->cyItem - (2 * pTree->cyBorder));
  776. ImageList_DrawEx(pTree->himlState, iState, hdc, x,
  777. y + max(pTree->cyItem - pTree->cyState, 0), dx, dy, clrBk, CLR_DEFAULT, ILD_NORMAL | (CCDPIScale(pTree->ci)?ILD_SCALE:0));
  778. x += pTree->cxState;
  779. }
  780. }
  781. if (pTree->hImageList)
  782. {
  783. UINT fStyle = 0;
  784. int i = (fSelectedIcon) ? ti.iSelectedImage : ti.iImage;
  785. if (ti.state & TVIS_CUT)
  786. {
  787. fStyle |= ILD_BLEND50;
  788. clrImage = ImageList_GetBkColor(pTree->hImageList);
  789. }
  790. dx = min(pTree->cxImage - MAGIC_INDENT, pTree->cxMax - pTree->cxBorder - x);
  791. dy = min(pTree->cyImage, pTree->cyItem - (2 * pTree->cyBorder));
  792. // Draw image stretched (rather than centered) when ImageList allows for scaling
  793. ImageList_DrawEx(pTree->hImageList, i, hdc,
  794. x + (dx - pTree->cxNativeImage) / 2, y + (max(pTree->cyItem - pTree->cyImage, 0) / 2) + (dy - pTree->cyNativeImage) / 2,
  795. pTree->cxNativeImage, pTree->cyNativeImage,
  796. clrBkImage, clrImage,
  797. fStyle | (ti.state & TVIS_OVERLAYMASK) | (CCDPIScale(pTree->ci)?ILD_SCALE:0));
  798. }
  799. }
  800. if (pTree->hImageList)
  801. {
  802. // even if not drawing image, draw text in right place
  803. x += pTree->cxImage;
  804. }
  805. // draw text
  806. lpstr = ti.pszText;
  807. cch = lstrlen(lpstr);
  808. if (!hItem->iWidth || (hItem->lpstr == LPSTR_TEXTCALLBACK))
  809. {
  810. TV_ComputeItemWidth(pTree, hItem, hdc); //$BOLD
  811. }
  812. rc.left = x;
  813. rc.top = y + pTree->cyBorder;
  814. rc.right = min((x + hItem->iWidth),
  815. (pTree->cxMax - pTree->cxBorder));
  816. rc.bottom-= pTree->cyBorder;
  817. // Draw the text, unless it's the one we are editing
  818. if (pTree->htiEdit != hItem || !IsWindow(pTree->hwndEdit) || !IsWindowVisible(pTree->hwndEdit))
  819. {
  820. ExtTextOut(hdc, x + g_cxLabelMargin, y + ((pTree->cyItem - pTree->cyText) / 2) + g_cyBorder,
  821. etoFlags, &rc, lpstr, cch, NULL);
  822. // Draw the focus rect, if appropriate.
  823. if (pTree->fFocus && (fItemFocused) &&
  824. !(pTree->ci.style & TVS_FULLROWSELECT) &&
  825. !(flags & (TVDI_TRANSTEXT | TVDI_GRAYCTL))&&
  826. !(CCGetUIState(&(pTree->ci)) & UISF_HIDEFOCUS))
  827. {
  828. DrawFocusRect(hdc, &rc);
  829. }
  830. }
  831. SetBkColor(hdc, rgbOldBack);
  832. SetTextColor(hdc, rgbOldText);
  833. // Restore the original font. //$BOLD
  834. SelectObject(hdc, hFont); //$BOLD
  835. // Notice that we should have opaque'd the rest of the line above if no tree
  836. if (!(flags & TVDI_NOTREE))
  837. {
  838. int dx, dy;
  839. if (pTree->hImageList)
  840. x -= pTree->cxImage;
  841. if (iState)
  842. x -= pTree->cxState;
  843. if (pTree->ci.style & TVS_HASLINES)
  844. {
  845. int i;
  846. x -= cxIndent;
  847. if (nmcd.iLevel-- || (pTree->ci.style & TVS_LINESATROOT))
  848. {
  849. // Special case the first root
  850. if (nmcd.iLevel == -1 && hItem == hItem->hParent->hKids)
  851. {
  852. if (hItem->hNext)
  853. {
  854. i = 2; // "L"
  855. if (ti.cChildren && (pTree->ci.style & TVS_HASBUTTONS))
  856. {
  857. i += 2; // "L+"
  858. if ((ti.state & (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) == TVIS_EXPANDED)
  859. i += 2; // "L-"
  860. }
  861. dx = min((int)cxIndent, pTree->cxMax - pTree->cxBorder - x);
  862. dy = pTree->cyItem - (2 * pTree->cyBorder);
  863. // Pass TRUE to draw the root ("L" upside down)
  864. TV_DrawState2(pTree, i, hdc, x, y, TRUE);
  865. i = -1;
  866. }
  867. else
  868. {
  869. // first root no siblings
  870. // if there's no other item, draw just the button if button mode,
  871. if (pTree->ci.style & TVS_HASBUTTONS)
  872. {
  873. if (ti.cChildren)
  874. {
  875. // hasbuttons, has lines, lines at root
  876. i = ((ti.state & (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) == TVIS_EXPANDED) ?
  877. 9 : 8; // ".--" : ".-+"
  878. }
  879. else
  880. {
  881. i = 7; // ".-"
  882. }
  883. }
  884. else
  885. {
  886. i = 3; // ".-"
  887. }
  888. }
  889. }
  890. else
  891. {
  892. i = (hItem->hNext) ? 1 : 2; // "|-" (rep) : "L"
  893. if (ti.cChildren && (pTree->ci.style & TVS_HASBUTTONS))
  894. {
  895. i += 2; // "|-+" (rep) : "L+"
  896. if ((ti.state & (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) == TVIS_EXPANDED)
  897. i += 2; // "|--" (rep) : "L-"
  898. }
  899. }
  900. if (hItem->iIntegral > 1)
  901. TV_DrawKinDescender(pTree, hdc, x, y, hItem, ti.state);
  902. if (i != -1)
  903. {
  904. dx = min((int)cxIndent, pTree->cxMax - pTree->cxBorder - x);
  905. dy = pTree->cyItem - (2 * pTree->cyBorder);
  906. if ((dx > 0) && (dy > 0))
  907. TV_DrawState(pTree, i, hdc, x, y);
  908. }
  909. while ((--nmcd.iLevel >= 0) || ((pTree->ci.style & TVS_LINESATROOT) && nmcd.iLevel >= -1))
  910. {
  911. hItem = hItem->hParent;
  912. x -= cxIndent;
  913. if (hItem->hNext)
  914. {
  915. dx = min((int)cxIndent, (pTree->cxMax - pTree->cxBorder - x));
  916. dy = min(pTree->cyItem, pTree->cyWnd - pTree->cyBorder - y);
  917. if ((dx > 0) && (dy > 0))
  918. TV_DrawState(pTree, 0, hdc, x, y);
  919. TV_DrawDescender(pTree, hdc, x, y, hItemSave);
  920. }
  921. }
  922. }
  923. }
  924. else
  925. { // no lines
  926. if ((pTree->ci.style & TVS_HASBUTTONS) && (nmcd.iLevel || pTree->ci.style & TVS_LINESATROOT)
  927. && ti.cChildren)
  928. {
  929. int i = ((ti.state & (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) == TVIS_EXPANDED) ? 1 : 0;
  930. x -= cxIndent;
  931. dx = min((int)cxIndent, pTree->cxMax - pTree->cxBorder - x);
  932. dy = min(pTree->cyItem, pTree->cyWnd - pTree->cyBorder - y);
  933. if ((dx > 0) && (dy > 0))
  934. TV_DrawState(pTree, i, hdc, x, y);
  935. }
  936. }
  937. }
  938. if (dwRet & CDRF_NOTIFYPOSTPAINT)
  939. {
  940. nmcd.nmcd.dwItemSpec = (DWORD_PTR)hItemSave;
  941. CICustomDrawNotify(&pTree->ci, CDDS_ITEMPOSTPAINT, &nmcd.nmcd);
  942. }
  943. SetBkMode(hdc, iOldBkMode);
  944. }
  945. #define INSERTMARKSIZE 6
  946. BOOL TV_GetInsertMarkRect(PTREE pTree, LPRECT prc)
  947. {
  948. ASSERT(pTree);
  949. if(pTree->htiInsert && TV_GetItemRect(pTree, pTree->htiInsert, prc, TRUE))
  950. {
  951. if (pTree->fInsertAfter)
  952. prc->top = prc->bottom;
  953. else
  954. prc->bottom = prc->top;
  955. prc->top -= INSERTMARKSIZE/2;
  956. prc->bottom += INSERTMARKSIZE/2 + 1;
  957. prc->right = pTree->cxWnd - INSERTMARKSIZE; // should always go all the way to right with pad.
  958. prc->left -= pTree->cxImage;
  959. return TRUE;
  960. }
  961. return FALSE;
  962. }
  963. __inline COLORREF TV_GetInsertMarkColor(PTREE pTree)
  964. {
  965. if (pTree->clrim == CLR_DEFAULT)
  966. return g_clrWindowText;
  967. else
  968. return pTree->clrim;
  969. }
  970. void TV_DrawTree(PTREE pTree, HDC hdc, BOOL fErase, LPRECT lprc)
  971. {
  972. int x;
  973. int iStart, iCnt;
  974. UINT uFlags;
  975. RECT rc;
  976. NMCUSTOMDRAW nmcd;
  977. if (!pTree->fRedraw)
  978. return;
  979. if (pTree->ci.style & TVS_CHECKBOXES)
  980. if (!pTree->himlState)
  981. TV_InitCheckBoxes(pTree);
  982. x = -pTree->xPos;
  983. TV_GetBackgroundBrush(pTree, hdc);
  984. rc = *lprc;
  985. iStart = lprc->top / pTree->cyItem;
  986. if (pTree->cItems && pTree->hTop)
  987. {
  988. ASSERT(ITEM_VISIBLE(pTree->hTop));
  989. iCnt = pTree->cShowing - pTree->hTop->iShownIndex;
  990. }
  991. else
  992. {
  993. iCnt = 0; // Nothing to draw
  994. }
  995. nmcd.hdc = hdc;
  996. /// not implemented yet
  997. //if (ptb->ci.hwnd == GetFocus())
  998. //nmcd.uItemState = CDIS_FOCUS;
  999. //else
  1000. nmcd.uItemState = 0;
  1001. nmcd.lItemlParam = 0;
  1002. nmcd.rc = rc;
  1003. pTree->ci.dwCustom = CICustomDrawNotify(&pTree->ci, CDDS_PREPAINT, &nmcd);
  1004. if (!(pTree->ci.dwCustom & CDRF_SKIPDEFAULT))
  1005. {
  1006. if (iStart <= iCnt)
  1007. {
  1008. HTREEITEM hItem;
  1009. HFONT hOldFont;
  1010. RECT rcT;
  1011. int y = 0;
  1012. for (hItem = pTree->hTop; hItem; )
  1013. {
  1014. if (iStart > hItem->iIntegral)
  1015. {
  1016. iStart -= hItem->iIntegral;
  1017. y += hItem->iIntegral * pTree->cyItem;
  1018. hItem = TV_GetNextVisItem(hItem);
  1019. } else
  1020. break;
  1021. }
  1022. hOldFont = pTree->hFont ? SelectObject(hdc, pTree->hFont) : NULL;
  1023. // TVDI_* for all items
  1024. uFlags = (pTree->ci.style & WS_DISABLED) ? TVDI_GRAYCTL : 0;
  1025. if (fErase)
  1026. uFlags |= TVDI_ERASE;
  1027. // loop from the first visible item until either all visible items are
  1028. // drawn or there are no more items to draw
  1029. for ( ; hItem && y < lprc->bottom; hItem = TV_GetNextVisItem(hItem))
  1030. {
  1031. TV_DrawItem(pTree, hItem, hdc, x, y, uFlags);
  1032. y += pTree->cyItem * hItem->iIntegral;
  1033. }
  1034. //
  1035. // handle drawing the InsertMark next to this item.
  1036. //
  1037. if(TV_GetInsertMarkRect(pTree, &rcT))
  1038. CCDrawInsertMark(hdc, &rcT, FALSE, TV_GetInsertMarkColor(pTree));
  1039. if (hOldFont)
  1040. SelectObject(hdc, hOldFont);
  1041. rc.top = y;
  1042. }
  1043. if (fErase)
  1044. // Opaque out everything we have not drawn explicitly
  1045. FillRect(hdc, &rc, pTree->hbrBk);
  1046. // notify parent afterwards if they want us to
  1047. if (pTree->ci.dwCustom & CDRF_NOTIFYPOSTPAINT) {
  1048. CICustomDrawNotify(&pTree->ci, CDDS_POSTPAINT, &nmcd);
  1049. }
  1050. }
  1051. }
  1052. // ----------------------------------------------------------------------------
  1053. //
  1054. // Set up for paint, call DrawTree, and clean up after paint.
  1055. //
  1056. // ----------------------------------------------------------------------------
  1057. void TV_Paint(PTREE pTree, HDC hdc)
  1058. {
  1059. PAINTSTRUCT ps;
  1060. if (hdc)
  1061. {
  1062. // hdc != 0 indicates a subclassed paint -- use the hdc passed in
  1063. SetRect(&ps.rcPaint, 0, 0, pTree->cxWnd, pTree->cyWnd);
  1064. TV_DrawTree(pTree, hdc, TRUE, &ps.rcPaint);
  1065. }
  1066. else
  1067. {
  1068. BeginPaint(pTree->ci.hwnd, &ps);
  1069. TV_DrawTree(pTree, ps.hdc, ps.fErase, &ps.rcPaint);
  1070. EndPaint(pTree->ci.hwnd, &ps);
  1071. }
  1072. }
  1073. // ----------------------------------------------------------------------------
  1074. // Create an imagelist to be used for dragging.
  1075. //
  1076. // 1) create mask and image bitmap matching the select bounds size
  1077. // 2) draw the text to both bitmaps (in black for now)
  1078. // 3) create an imagelist with these bitmaps
  1079. // 4) make a dithered copy of the image onto the new imagelist
  1080. // ----------------------------------------------------------------------------
  1081. HIMAGELIST TV_CreateDragImage(PTREE pTree, HTREEITEM hItem)
  1082. {
  1083. HDC hdcMem = NULL;
  1084. HBITMAP hbmImage = NULL;
  1085. HBITMAP hbmMask = NULL;
  1086. HBITMAP hbmOld;
  1087. HIMAGELIST himl = NULL;
  1088. BOOL bMirroredWnd = (pTree->ci.dwExStyle&RTL_MIRRORED_WINDOW);
  1089. int dx, dy;
  1090. int iSrc;
  1091. TVITEMEX ti;
  1092. if (!pTree->hImageList)
  1093. return NULL;
  1094. if (hItem == NULL)
  1095. hItem = pTree->htiDrag;
  1096. if (hItem == NULL)
  1097. return NULL;
  1098. dx = hItem->iWidth + pTree->cxImage;
  1099. dy = pTree->cyItem;
  1100. if (!(hdcMem = CreateCompatibleDC(NULL)))
  1101. goto CDI_Exit;
  1102. if (!(hbmImage = CreateColorBitmap(dx, dy)))
  1103. goto CDI_Exit;
  1104. if (!(hbmMask = CreateMonoBitmap(dx, dy)))
  1105. goto CDI_Exit;
  1106. //
  1107. // Mirror the memory DC so that the transition from
  1108. // mirrored(memDC)->non-mirrored(imagelist DCs)->mirrored(screenDC)
  1109. // is consistent. [samera]
  1110. //
  1111. if (bMirroredWnd) {
  1112. SET_DC_RTL_MIRRORED(hdcMem);
  1113. }
  1114. // prepare for drawing the item
  1115. if (pTree->hFont)
  1116. SelectObject(hdcMem, pTree->hFont);
  1117. SetBkMode(hdcMem, TRANSPARENT);
  1118. /*
  1119. ** draw the text to both bitmaps
  1120. */
  1121. hbmOld = SelectObject(hdcMem, hbmImage);
  1122. // fill image with black for transparency
  1123. PatBlt(hdcMem, 0, 0, dx, dy, BLACKNESS);
  1124. TV_DrawItem(pTree, hItem, hdcMem, 0, 0,
  1125. TVDI_NOIMAGE | TVDI_NOTREE | TVDI_TRANSTEXT);
  1126. //
  1127. // If the header is RTL mirrored, then
  1128. // mirror the Memory DC, so that when copying back
  1129. // we don't get any image-flipping. [samera]
  1130. //
  1131. if (bMirroredWnd)
  1132. MirrorBitmapInDC(hdcMem, hbmImage);
  1133. SelectObject(hdcMem, hbmMask);
  1134. // fill mask with white for transparency
  1135. PatBlt(hdcMem, 0, 0, dx, dy, WHITENESS);
  1136. TV_DrawItem(pTree, hItem, hdcMem, 0, 0,
  1137. TVDI_NOIMAGE | TVDI_NOTREE | TVDI_TRANSTEXT);
  1138. //
  1139. // If the header is RTL mirrored, then
  1140. // mirror the Memory DC, so that when copying back
  1141. // we don't get any image-flipping. [samera]
  1142. //
  1143. if (bMirroredWnd)
  1144. MirrorBitmapInDC(hdcMem, hbmMask);
  1145. // unselect objects that we used
  1146. SelectObject(hdcMem, hbmOld);
  1147. SelectObject(hdcMem, g_hfontSystem);
  1148. /*
  1149. ** make an image list that for now only has the text
  1150. */
  1151. if (!(himl = ImageList_Create(dx, dy, ILC_MASK, 1, 0)))
  1152. goto CDI_Exit;
  1153. ImageList_SetBkColor(himl, CLR_NONE);
  1154. ImageList_Add(himl, hbmImage, hbmMask);
  1155. /*
  1156. ** make a dithered copy of the image part onto our bitmaps
  1157. ** (need both bitmap and mask to be dithered)
  1158. */
  1159. TV_GetItem(pTree, hItem, TVIF_IMAGE, &ti);
  1160. iSrc = ti.iImage;
  1161. ImageList_CopyDitherImage(himl, 0, 0, (pTree->cyItem - pTree->cyImage) / 2,
  1162. pTree->hImageList, iSrc, ((pTree->ci.dwExStyle & dwExStyleRTLMirrorWnd) ? ILD_MIRROR : 0L) | (hItem->state & TVIS_OVERLAYMASK));
  1163. CDI_Exit:
  1164. if (hdcMem)
  1165. DeleteObject(hdcMem);
  1166. if (hbmImage)
  1167. DeleteObject(hbmImage);
  1168. if (hbmMask)
  1169. DeleteObject(hbmMask);
  1170. return himl;
  1171. }
  1172. #define COLORKEY RGB(0xF4, 0x0, 0x0)
  1173. LRESULT TV_GenerateDragImage(PTREE pTree, SHDRAGIMAGE* pshdi)
  1174. {
  1175. LRESULT lRet = 0;
  1176. HBITMAP hbmpOld = NULL;
  1177. HTREEITEM hItem = pTree->htiDrag;
  1178. RECT rc;
  1179. HDC hdcDragImage;
  1180. if (hItem == NULL)
  1181. return FALSE;
  1182. hdcDragImage = CreateCompatibleDC(NULL);
  1183. if (!hdcDragImage)
  1184. return 0;
  1185. // After this rc contains the bounds of all the items in Client Coordinates.
  1186. //
  1187. // Mirror the the DC, if the listview is mirrored.
  1188. //
  1189. if (pTree->ci.dwExStyle & RTL_MIRRORED_WINDOW)
  1190. {
  1191. SET_DC_RTL_MIRRORED(hdcDragImage);
  1192. }
  1193. TV_GetItemRect(pTree, hItem, &rc, TRUE);
  1194. // Subtract off the image...
  1195. rc.left -= pTree->cxImage;
  1196. pshdi->sizeDragImage.cx = RECTWIDTH(rc);
  1197. pshdi->sizeDragImage.cy = RECTHEIGHT(rc);
  1198. pshdi->hbmpDragImage = CreateBitmap( pshdi->sizeDragImage.cx, pshdi->sizeDragImage.cy,
  1199. GetDeviceCaps(hdcDragImage, PLANES), GetDeviceCaps(hdcDragImage, BITSPIXEL),
  1200. NULL);
  1201. if (pshdi->hbmpDragImage)
  1202. {
  1203. COLORREF clrBkSave;
  1204. RECT rcImage = {0, 0, pshdi->sizeDragImage.cx, pshdi->sizeDragImage.cy};
  1205. hbmpOld = SelectObject(hdcDragImage, pshdi->hbmpDragImage);
  1206. pshdi->crColorKey = COLORKEY;
  1207. FillRectClr(hdcDragImage, &rcImage, pshdi->crColorKey);
  1208. // Calculate the offset... The cursor should be in the bitmap rect.
  1209. if (pTree->ci.dwExStyle & RTL_MIRRORED_WINDOW)
  1210. pshdi->ptOffset.x = rc.right - pTree->ptCapture.x;
  1211. else
  1212. pshdi->ptOffset.x = pTree->ptCapture.x - rc.left;
  1213. pshdi->ptOffset.y = pTree->ptCapture.y - rc.top;
  1214. clrBkSave = pTree->clrBk;
  1215. pTree->clrBk = COLORKEY;
  1216. TV_DrawItem(pTree, hItem, hdcDragImage, 0, 0,
  1217. TVDI_NOTREE | TVDI_TRANSTEXT | TVDI_FORCEIMAGE | TVDI_NOBK);
  1218. pTree->clrBk = clrBkSave;
  1219. SelectObject(hdcDragImage, hbmpOld);
  1220. DeleteDC(hdcDragImage);
  1221. // We're passing back the created HBMP.
  1222. return 1;
  1223. }
  1224. return lRet;
  1225. }