Source code of Windows XP (NT5)
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.

4639 lines
129 KiB

  1. #include "ctlspriv.h"
  2. #include "rebar.h"
  3. #include "image.h"
  4. #ifdef DEBUG
  5. int ExprASSERT(int e);
  6. BOOL RBCheckRangePtr(PRB prb, PRBB prbb);
  7. BOOL RBCheckRangeInd(PRB prb, INT_PTR i);
  8. #else
  9. #define ExprASSERT(e) 0
  10. #define RBCheckRangePtr(prb, prbb) 0
  11. #define RBCheckRangeInd(prb, i) 0
  12. #endif
  13. #define RBBUSECHEVRON(prb, prbb) ((prbb->fStyle & RBBS_USECHEVRON) && \
  14. !((prbb)->fStyle & RBBS_FIXEDSIZE) && \
  15. ((UINT)(prbb)->cxIdeal > (prbb)->cxMinChild))
  16. #define RBSHOWTEXT(prbb) (!(prbb->fStyle&RBBS_HIDETITLE) && prbb->lpText && prbb->lpText[0])
  17. #define CX_CHEVRON (5 * g_cxEdge + 2)
  18. #define CX_OFFSET (2 * g_cxEdge)
  19. #define RB_GRABWIDTH 5
  20. #define RB_ISVERT(prb) ((prb)->ci.style & CCS_VERT)
  21. #define RB_ISVERTICALGRIPPER(prb) (RB_ISVERT(prb) && (prb)->ci.style & RBS_VERTICALGRIPPER)
  22. #define RB_GETLASTBAND(prb) ((prb)->cBands ? RBGETBAND(prb, (prb)->cBands -1) : NULL)
  23. #define RBISBANDSTARTOFROW(prbb) (!((prbb)->x) && !((prbb)->fStyle & RBBS_HIDDEN))
  24. #define RBGETBAND(prb, i) (ExprASSERT(RBCheckRangeInd(prb, i)), &(prb)->rbbList[i])
  25. #define RBISSTARTOFROW(prb, i) (RBISBANDSTARTOFROW( RBGETBAND((prb), (i))))
  26. #define RBGETFIRSTBAND(prb) (RBGETBAND(prb, 0))
  27. #define RBBANDTOINDEX(prb, prbb) ((int)((prbb) - (prb)->rbbList))
  28. #define RBBHEADERWIDTH(prbb) ((prbb)->cxMin - ((prbb)->cxMinChild + ((RBBUSECHEVRON(prb, prbb) ? CX_CHEVRON : 0))))
  29. #define RBISBANDVISIBLE(prbb) (!((prbb)->fStyle & RBBS_HIDDEN))
  30. #define RBROWATMINHEIGHT(prb, pprbb) (!RBGetRowHeightExtra(prb, pprbb, NULL))
  31. #define RBGETBARHEIGHT(prb) (((prb)->cBands && !(prb)->cy) ? RBRecalc(prb) : (prb)->cy)
  32. #define RB_ISVALIDINDEX(prb, i) ((UINT)i < (prb)->cBands)
  33. #define RB_ISVALIDBAND(prb, prbb) RB_ISVALIDINDEX(prb, RBBANDTOINDEX(prb, prbb))
  34. #define RB_ANIMSTEPS 10
  35. #define RB_ANIMSTEPTIME 5
  36. void FlipRect(LPRECT prc);
  37. void RBPassBreak(PRB prb, PRBB prbbSrc, PRBB prbbDest);
  38. int RBHitTest(PRB prb, LPRBHITTESTINFO prbht);
  39. BOOL RBSizeBandsToRect(PRB prb, LPRECT prc);
  40. BOOL RBShouldDrawGripper(PRB prb, PRBB prbb);
  41. void RBAutoSize(PRB prb);
  42. void RBSizeBandsToRowHeight(PRB prb);
  43. void RBSizeBandToRowHeight(PRB prb, int i, UINT uRowHeight);
  44. BOOL RBSetBandPos(PRB prb, PRBB prbb, int xLeft);
  45. BOOL RBSetBandPosAnim(PRB prb, PRBB prbb, int xLeft);
  46. PRBB RBGetFirstInRow(PRB prb, PRBB prbbRow);
  47. PRBB RBGetLastInRow(PRB prb, PRBB prbbRow, BOOL fStopAtFixed);
  48. PRBB RBGetPrev(PRB prb, PRBB prbb, UINT uStyleSkip);
  49. PRBB RBGetNext(PRB prb, PRBB prbb, UINT uStyleSkip);
  50. PRBB RBEnumBand(PRB prb, int i, UINT uStyleSkip);
  51. int RBCountBands(PRB prb, UINT uStyleSkip);
  52. BOOL RBMaximizeBand(PRB prb, UINT uBand, BOOL fIdeal, BOOL fAnim);
  53. PRBB RBGetNextVisible(PRB prb, PRBB prbb);
  54. PRBB RBGetPrevVisible(PRB prb, PRBB prbb);
  55. PRBB RBBNextVisible(PRB prb, PRBB prbb);
  56. BOOL RBShowBand(PRB prb, UINT uBand, BOOL fShow);
  57. void RBGetClientRect(PRB prb, LPRECT prc);
  58. int RBGetRowHeightExtra(PRB prb, PRBB *pprbb, PRBB prbbSkip);
  59. void RBOnBeginDrag(PRB prb, UINT uBand);
  60. #define RBBANDWIDTH(prb, prbb) _RBBandWidth(prb, prbb->cx)
  61. #ifdef DEBUG
  62. #undef RBBANDWIDTH
  63. #define RBBANDWIDTH(prb, prbb) \
  64. ((prbb->fStyle & RBBS_HIDDEN) ? (ExprASSERT(0), -1) : \
  65. _RBBandWidth(prb, prbb->cx))
  66. #endif
  67. #define RBBANDMINWIDTH(prb, prbb) _RBBandWidth(prb, prbb->cxMin)
  68. #ifdef DEBUG
  69. #undef RBBANDMINWIDTH
  70. #define RBBANDMINWIDTH(prb, prbb) \
  71. ((prbb->fStyle & RBBS_HIDDEN) ? (ExprASSERT(0), -1) : \
  72. _RBBandWidth(prb, prbb->cxMin))
  73. #endif
  74. //*** RBC_* -- commands
  75. #define RBC_QUERY 0
  76. #define RBC_SET 1
  77. #ifdef DEBUG
  78. int ExprASSERT(int e)
  79. {
  80. ASSERT(e);
  81. return 0;
  82. }
  83. #endif
  84. HBRUSH g_hDPFRBrush = NULL;
  85. __inline COLORREF RB_GetBkColor(PRB prb)
  86. {
  87. if (prb->clrBk == CLR_DEFAULT)
  88. return g_clrBtnFace;
  89. else
  90. return prb->clrBk;
  91. }
  92. __inline COLORREF RB_GetTextColor(PRB prb)
  93. {
  94. if (prb->clrText == CLR_DEFAULT)
  95. return g_clrBtnText;
  96. else
  97. return prb->clrText;
  98. }
  99. __inline COLORREF RBB_GetBkColor(PRB prb, PRBB prbb)
  100. {
  101. switch(prbb->clrBack)
  102. {
  103. case CLR_NONE:
  104. // CLR_NONE means "use our dad's color"
  105. return RB_GetBkColor(prb);
  106. case CLR_DEFAULT:
  107. return g_clrBtnFace;
  108. default:
  109. return prbb->clrBack;
  110. }
  111. }
  112. __inline COLORREF RBB_GetTextColor(PRB prb, PRBB prbb)
  113. {
  114. switch (prbb->clrFore)
  115. {
  116. case CLR_NONE:
  117. // CLR_NONE means "use our dad's color"
  118. return RB_GetTextColor(prb);
  119. case CLR_DEFAULT:
  120. return g_clrBtnText;
  121. default:
  122. return prbb->clrFore;
  123. }
  124. }
  125. //
  126. // Our use of CLR_DEFAULT for the band background colors is new for
  127. // version 5.01. Since we don't want to confuse apps by returning
  128. // CLR_DEFAULT when they used to see a real colorref, we convert it
  129. // before returning it to them. If the background color is CLR_NONE,
  130. // though, we need to return it without conversion (like version 4 did).
  131. // The *_External functions handle these cases.
  132. //
  133. __inline COLORREF RBB_GetTextColor_External(PRB prb, PRBB prbb)
  134. {
  135. if (prbb->clrFore == CLR_NONE)
  136. return CLR_NONE;
  137. else
  138. return RBB_GetTextColor(prb, prbb);
  139. }
  140. __inline COLORREF RBB_GetBkColor_External(PRB prb, PRBB prbb)
  141. {
  142. if (prbb->clrBack == CLR_NONE)
  143. return CLR_NONE;
  144. else
  145. return RBB_GetBkColor(prb, prbb);
  146. }
  147. ///
  148. //
  149. // Implement MapWindowPoints as if the hwndFrom and hwndTo aren't
  150. // mirrored. This is used when any of the windows (hwndFrom or hwndTo)
  151. // are mirrored. See below. [samera]
  152. //
  153. int TrueMapWindowPoints(HWND hwndFrom, HWND hwndTo, LPPOINT lppt, UINT cPoints)
  154. {
  155. int dx, dy;
  156. RECT rcFrom={0,0,0,0}, rcTo={0,0,0,0};
  157. if (hwndFrom) {
  158. GetClientRect(hwndFrom, &rcFrom);
  159. MapWindowPoints(hwndFrom, NULL, (LPPOINT)&rcFrom.left, 2);
  160. }
  161. if (hwndTo) {
  162. GetClientRect(hwndTo, &rcTo);
  163. MapWindowPoints(hwndTo, NULL, (LPPOINT)&rcTo.left, 2);
  164. }
  165. dx = rcFrom.left - rcTo.left;
  166. dy = rcFrom.top - rcTo.top;
  167. /*
  168. * Map the points
  169. */
  170. while (cPoints--) {
  171. lppt->x += dx;
  172. lppt->y += dy;
  173. ++lppt;
  174. }
  175. return MAKELONG(dx, dy);
  176. }
  177. ///
  178. //
  179. // Map a rect to parent should be based on the visual right edge
  180. // for calculating the client coordinates for a RTL mirrored windows.
  181. // This routine should only be used when calculating client
  182. // coordinates in a RTL mirrored window. [samera]
  183. //
  184. BOOL MapRectInRTLMirroredWindow( LPRECT lprc, HWND hwnd)
  185. {
  186. int iWidth = lprc->right - lprc->left;
  187. int iHeight = lprc->bottom- lprc->top;
  188. RECT rc={0,0,0,0};
  189. if (hwnd) {
  190. GetClientRect(hwnd, &rc);
  191. MapWindowPoints(hwnd, NULL, (LPPOINT)&rc.left, 2);
  192. }
  193. lprc->left = rc.right - lprc->right;
  194. lprc->top = lprc->top-rc.top;
  195. lprc->bottom = lprc->top + iHeight;
  196. lprc->right = lprc->left + iWidth;
  197. return TRUE;
  198. }
  199. int _RBBandWidth(PRB prb, int x)
  200. {
  201. if (prb->ci.style & RBS_BANDBORDERS)
  202. x += g_cxEdge;
  203. return x;
  204. }
  205. void RBRealize(PRB prb, HDC hdcParam, BOOL fBackground, BOOL fForceRepaint)
  206. {
  207. if (prb->hpal)
  208. {
  209. HDC hdc = hdcParam ? hdcParam : GetDC(prb->ci.hwnd);
  210. if (hdc)
  211. {
  212. BOOL fRepaint;
  213. SelectPalette(hdc, prb->hpal, fBackground);
  214. fRepaint = RealizePalette(hdc) || fForceRepaint;
  215. if (!hdcParam)
  216. ReleaseDC(prb->ci.hwnd, hdc);
  217. if (fRepaint)
  218. {
  219. InvalidateRect(prb->ci.hwnd, NULL, TRUE);
  220. }
  221. }
  222. }
  223. }
  224. //////////////////////////////////////////////////////////////////
  225. // RBSendNotify
  226. //
  227. // sends a wm_notify of code iCode and packages up all the data for you
  228. // for band uBand
  229. //
  230. //////////////////////////////////////////////////////////////////
  231. LRESULT RBSendNotify(PRB prb, UINT uBand, int iCode)
  232. {
  233. NMREBAR nm = {0};
  234. nm.uBand = uBand;
  235. if (uBand != (UINT)-1) {
  236. nm.dwMask = RBNM_ID | RBNM_STYLE | RBNM_LPARAM;
  237. nm.wID = RBGETBAND(prb, uBand)->wID;
  238. nm.fStyle = RBGETBAND(prb, uBand)->fStyle;
  239. nm.lParam = RBGETBAND(prb, uBand)->lParam;
  240. }
  241. return CCSendNotify(&prb->ci, iCode, &nm.hdr);
  242. }
  243. BOOL RBInvalidateRect(PRB prb, RECT* prc)
  244. {
  245. if (prb->fRedraw)
  246. {
  247. RECT rc;
  248. if (prc && RB_ISVERT(prb))
  249. {
  250. CopyRect(&rc, prc);
  251. FlipRect(&rc);
  252. prc = &rc;
  253. }
  254. prb->fRefreshPending = FALSE;
  255. InvalidateRect(prb->ci.hwnd, prc, TRUE);
  256. return TRUE;
  257. }
  258. else
  259. {
  260. prb->fRefreshPending = TRUE;
  261. return FALSE;
  262. }
  263. }
  264. LRESULT RebarDragCallback(HWND hwnd, UINT code, WPARAM wp, LPARAM lp)
  265. {
  266. PRB prb = (PRB)GetWindowPtr(hwnd, 0);
  267. LRESULT lres;
  268. switch (code)
  269. {
  270. case DPX_DRAGHIT:
  271. if (lp)
  272. {
  273. int iBand;
  274. RBHITTESTINFO rbht;
  275. rbht.pt.x = ((POINTL *)lp)->x;
  276. rbht.pt.y = ((POINTL *)lp)->y;
  277. MapWindowPoints(NULL, prb->ci.hwnd, &rbht.pt, 1);
  278. iBand = RBHitTest(prb, &rbht);
  279. *(DWORD*)wp = rbht.flags;
  280. lres = (LRESULT)(iBand != -1 ? prb->rbbList[iBand].wID : -1);
  281. }
  282. else
  283. lres = -1;
  284. break;
  285. case DPX_GETOBJECT:
  286. lres = (LRESULT)GetItemObject(&prb->ci, RBN_GETOBJECT, &IID_IDropTarget, (LPNMOBJECTNOTIFY)lp);
  287. break;
  288. default:
  289. lres = -1;
  290. break;
  291. }
  292. return lres;
  293. }
  294. // ----------------------------------------------------------------------------
  295. //
  296. // RBCanBandMove
  297. //
  298. // returns TRUE if the given band can be moved and FALSE if it cannot
  299. //
  300. // ----------------------------------------------------------------------------
  301. BOOL RBCanBandMove(PRB prb, PRBB prbb)
  302. {
  303. // If there is only one visible band it cannot move
  304. if (RBEnumBand(prb, 1, RBBS_HIDDEN) > RB_GETLASTBAND(prb))
  305. return FALSE;
  306. ASSERT(!(prbb->fStyle & RBBS_HIDDEN));
  307. if ((prb->ci.style & RBS_FIXEDORDER)
  308. && (prbb == RBEnumBand(prb, 0, RBBS_HIDDEN)))
  309. // the first (visible) band in fixed order rebars can't be moved
  310. return(FALSE);
  311. // fixed size bands can't be moved
  312. return(!(prbb->fStyle & RBBS_FIXEDSIZE));
  313. }
  314. // ----------------------------------------------------------------------------
  315. //
  316. // RBBCalcMinWidth
  317. //
  318. // calculates minimum width for the given band
  319. //
  320. // ----------------------------------------------------------------------------
  321. void RBBCalcMinWidth(PRB prb, PRBB prbb)
  322. {
  323. BOOL fDrawGripper = RBShouldDrawGripper(prb, prbb);
  324. BOOL fVertical;
  325. int cEdge;
  326. BOOL fEmpty = ((prbb->iImage == -1) && (!RBSHOWTEXT(prbb)));
  327. if (prbb->fStyle & RBBS_HIDDEN) {
  328. ASSERT(0);
  329. return;
  330. }
  331. // did the user specify the size explicitly?
  332. if (prbb->fStyle & RBBS_FIXEDHEADERSIZE)
  333. return;
  334. prbb->cxMin = prbb->cxMinChild;
  335. if (RBBUSECHEVRON(prb, prbb))
  336. prbb->cxMin += CX_CHEVRON;
  337. if (!fDrawGripper && fEmpty)
  338. return;
  339. fVertical = (prb->ci.style & CCS_VERT);
  340. if (RB_ISVERTICALGRIPPER(prb)) {
  341. prbb->cxMin += 4 * g_cyEdge;
  342. prbb->cxMin += max(prb->cyImage, prb->cyFont);
  343. } else {
  344. cEdge = fVertical ? g_cyEdge : g_cxEdge;
  345. prbb->cxMin += 2 * cEdge;
  346. if (fDrawGripper)
  347. {
  348. prbb->cxMin += RB_GRABWIDTH * (fVertical ? g_cyBorder : g_cxBorder);
  349. if (fEmpty)
  350. return;
  351. }
  352. prbb->cxMin += 2 * cEdge;
  353. if (prbb->iImage != -1)
  354. prbb->cxMin += (fVertical ? prb->cyImage : prb->cxImage);
  355. if (RBSHOWTEXT(prbb))
  356. {
  357. if (fVertical)
  358. prbb->cxMin += prb->cyFont;
  359. else
  360. prbb->cxMin += prbb->cxText;
  361. if (prbb->iImage != -1)
  362. // has both image and text -- add in edge between 'em
  363. prbb->cxMin += cEdge;
  364. }
  365. }
  366. }
  367. BOOL RBShouldDrawGripper(PRB prb, PRBB prbb)
  368. {
  369. if (prbb->fStyle & RBBS_NOGRIPPER)
  370. return FALSE;
  371. if ((prbb->fStyle & RBBS_GRIPPERALWAYS) || RBCanBandMove(prb, prbb))
  372. return TRUE;
  373. return FALSE;
  374. }
  375. // ----------------------------------------------------------------------------
  376. //
  377. // RBBCalcTextExtent
  378. //
  379. // computes the horizontal extent of the given band's title text in the current
  380. // title font for the rebar
  381. //
  382. // returns TRUE if text extent changed, FALSE otherwise
  383. //
  384. // ----------------------------------------------------------------------------
  385. BOOL RBBCalcTextExtent(PRB prb, PRBB prbb, HDC hdcIn)
  386. {
  387. HDC hdc = hdcIn;
  388. HFONT hFontOld;
  389. UINT cx;
  390. if (prbb->fStyle & RBBS_HIDDEN)
  391. {
  392. ASSERT(0); // caller should have skipped
  393. return FALSE;
  394. }
  395. if (!RBSHOWTEXT(prbb))
  396. {
  397. cx = 0;
  398. }
  399. else
  400. {
  401. if (!hdcIn && !(hdc = GetDC(prb->ci.hwnd)))
  402. return FALSE;
  403. hFontOld = SelectObject(hdc, prb->hFont);
  404. // for clients >= v5, we draw text with prefix processing (& underlines next char)
  405. if (prb->ci.iVersion >= 5)
  406. {
  407. RECT rc = {0,0,0,0};
  408. DrawText(hdc, prbb->lpText, lstrlen(prbb->lpText), &rc, DT_CALCRECT);
  409. cx = RECTWIDTH(rc);
  410. }
  411. else
  412. {
  413. SIZE size;
  414. GetTextExtentPoint(hdc, prbb->lpText, lstrlen(prbb->lpText), &size);
  415. cx = size.cx;
  416. }
  417. SelectObject(hdc, hFontOld);
  418. if (!hdcIn)
  419. ReleaseDC(prb->ci.hwnd, hdc);
  420. }
  421. if (prbb->cxText != cx)
  422. {
  423. prbb->cxText = cx;
  424. RBBCalcMinWidth(prb, prbb);
  425. return TRUE;
  426. }
  427. return FALSE;
  428. }
  429. // ----------------------------------------------------------------------------
  430. //
  431. // RBBGetHeight
  432. //
  433. // returns minimum height for the given band
  434. // TODO: make this a field in the band structure instead of always calling this
  435. //
  436. // ----------------------------------------------------------------------------
  437. UINT RBBGetHeight(PRB prb, PRBB prbb)
  438. {
  439. UINT cy = 0;
  440. BOOL fVertical = (prb->ci.style & CCS_VERT);
  441. UINT cyCheck, cyBorder;
  442. cyBorder = (fVertical ? g_cxEdge : g_cyEdge) * 2;
  443. if (prbb->hwndChild)
  444. {
  445. cy = prbb->cyChild;
  446. if (!(prbb->fStyle & RBBS_CHILDEDGE))
  447. // add edge to top and bottom of child window
  448. cy -= cyBorder;
  449. }
  450. if (RBSHOWTEXT(prbb) && !fVertical)
  451. {
  452. cyCheck = prb->cyFont;
  453. if (cyCheck > cy)
  454. cy = cyCheck;
  455. }
  456. if (prbb->iImage != -1)
  457. {
  458. cyCheck = (fVertical) ? prb->cxImage : prb->cyImage;
  459. if (cyCheck > cy)
  460. cy = cyCheck;
  461. }
  462. return(cy + cyBorder);
  463. }
  464. // ----------------------------------------------------------------------------
  465. //
  466. // RBGetRowCount
  467. //
  468. // returns the number of rows in the rebar's current configuration
  469. //
  470. // ----------------------------------------------------------------------------
  471. UINT RBGetRowCount(PRB prb)
  472. {
  473. UINT i;
  474. UINT cRows = 0;
  475. for (i = 0; i < prb->cBands; i++) {
  476. if (RBGETBAND(prb, i)->fStyle & RBBS_HIDDEN)
  477. continue;
  478. if (RBISSTARTOFROW(prb, i))
  479. cRows++;
  480. }
  481. return(cRows);
  482. }
  483. // ----------------------------------------------------------------------------
  484. //
  485. // RBGetLineHeight
  486. //
  487. // returns the height of the line of bands from iStart to iEnd, inclusively
  488. //
  489. // ----------------------------------------------------------------------------
  490. UINT RBGetLineHeight(PRB prb, UINT iStart, UINT iEnd)
  491. {
  492. UINT cy = 0;
  493. PRBB prbb;
  494. UINT cyBand;
  495. if (!(prb->ci.style & RBS_VARHEIGHT))
  496. {
  497. // for fixed height bars, line height is maximum height of ALL bands
  498. iStart = 0;
  499. iEnd = prb->cBands - 1;
  500. }
  501. for (prbb = prb->rbbList + iStart; iStart <= iEnd; prbb++, iStart++)
  502. {
  503. if (prbb->fStyle & RBBS_HIDDEN)
  504. continue;
  505. cyBand = RBBGetHeight(prb, prbb);
  506. cy = max(cy, cyBand);
  507. }
  508. return(cy);
  509. }
  510. // RBRecalcChevron: update & refresh chevron
  511. void RBRecalcChevron(PRB prb, PRBB prbb, BOOL fChevron)
  512. {
  513. RECT rcChevron;
  514. if (fChevron)
  515. {
  516. rcChevron.right = prbb->x + prbb->cx;
  517. rcChevron.left = rcChevron.right - CX_CHEVRON;
  518. rcChevron.top = prbb->y;
  519. rcChevron.bottom = rcChevron.top + prbb->cy;
  520. }
  521. else
  522. SetRect(&rcChevron, -1, -1, -1, -1);
  523. if (!EqualRect(&rcChevron, &prbb->rcChevron))
  524. {
  525. if (prbb->fChevron)
  526. RBInvalidateRect(prb, &prbb->rcChevron);
  527. prbb->fChevron = fChevron;
  528. CopyRect(&prbb->rcChevron, &rcChevron);
  529. if (prbb->fChevron)
  530. RBInvalidateRect(prb, &prbb->rcChevron);
  531. }
  532. }
  533. // ----------------------------------------------------------------------------
  534. //
  535. // RBResizeChildren
  536. //
  537. // resizes children to fit properly in their respective bands' bounding rects
  538. //
  539. // ----------------------------------------------------------------------------
  540. void RBResizeChildren(PRB prb)
  541. {
  542. int cx, cy, x, y, cxHeading;
  543. HDWP hdwp;
  544. BOOL fVertical = (prb->ci.style & CCS_VERT);
  545. PRBB prbb, prbbEnd;
  546. if (!prb->cBands || !prb->fRedraw)
  547. return;
  548. hdwp = BeginDeferWindowPos(prb->cBands);
  549. prbb = RBGETBAND(prb, 0);
  550. prbbEnd = RB_GETLASTBAND(prb);
  551. for ( ; prbb <= prbbEnd ; prbb++)
  552. {
  553. NMREBARCHILDSIZE nm;
  554. BOOL fChevron = FALSE;
  555. if (prbb->fStyle & RBBS_HIDDEN)
  556. continue;
  557. if (!prbb->hwndChild)
  558. continue;
  559. cxHeading = RBBHEADERWIDTH(prbb);
  560. x = prbb->x + cxHeading;
  561. cx = prbb->cx - cxHeading;
  562. // if we're not giving child ideal size, make space for chevron button
  563. if ((cx < prbb->cxIdeal) && RBBUSECHEVRON(prb, prbb))
  564. {
  565. fChevron = TRUE;
  566. cx -= CX_CHEVRON;
  567. }
  568. if (!(prbb->fStyle & RBBS_FIXEDSIZE)) {
  569. if (fVertical) {
  570. PRBB prbbNext = RBBNextVisible(prb, prbb);
  571. if (prbbNext && !RBISBANDSTARTOFROW(prbbNext))
  572. cx -= g_cyEdge * 2;
  573. } else
  574. cx -= CX_OFFSET;
  575. }
  576. if (cx < 0)
  577. cx = 0;
  578. y = prbb->y;
  579. cy = prbb->cy;
  580. if (prbb->cyChild && (prbb->cyChild < (UINT) cy))
  581. {
  582. y += (cy - prbb->cyChild) / 2;
  583. cy = prbb->cyChild;
  584. }
  585. nm.rcChild.left = x;
  586. nm.rcChild.top = y;
  587. nm.rcChild.right = x + cx;
  588. nm.rcChild.bottom = y + cy;
  589. nm.rcBand.left = prbb->x + RBBHEADERWIDTH(prbb);
  590. nm.rcBand.right = prbb->x + prbb->cx;
  591. nm.rcBand.top = prbb->y;
  592. nm.rcBand.bottom = prbb->y + prbb->cy;
  593. nm.uBand = RBBANDTOINDEX(prb, prbb);
  594. nm.wID = prbb->wID;
  595. if (fVertical) {
  596. FlipRect(&nm.rcChild);
  597. FlipRect(&nm.rcBand);
  598. }
  599. CCSendNotify(&prb->ci, RBN_CHILDSIZE, &nm.hdr);
  600. if (!RB_ISVALIDBAND(prb, prbb)) {
  601. // somebody responded to notify by nuking bands; bail
  602. break;
  603. }
  604. RBRecalcChevron(prb, prbb, fChevron);
  605. DeferWindowPos(hdwp, prbb->hwndChild, NULL, nm.rcChild.left, nm.rcChild.top,
  606. RECTWIDTH(nm.rcChild), RECTHEIGHT(nm.rcChild), SWP_NOZORDER);
  607. }
  608. EndDeferWindowPos(hdwp);
  609. //
  610. // The SQL 7.0 Enterprise Manager Data Transformation Services MMC Snap-In
  611. // (and the Visual Basic Coolbar Sample App, too) has problems.
  612. // It hosts a rebar but doesn't set the WS_CLIPCHILDREN flag,
  613. // so when it erases its background, it wipes out the rebar. So don't
  614. // call UpdateWindow() here, or we will paint *first*, then SQL will
  615. // erase us by mistake. We have to leave our paint pending, so that
  616. // when SQL erases us by mistake, we will eventually get a WM_PAINT
  617. // message afterwards.
  618. //
  619. #if 0
  620. UpdateWindow(prb->ci.hwnd);
  621. #endif
  622. }
  623. // ----------------------------------------------------------------------------
  624. //
  625. // RBMoveBand
  626. //
  627. // moves the band from one position to another in the rebar's band array,
  628. // updating the rebar's iCapture field as needed
  629. //
  630. // returns TRUE or FALSE if something moved
  631. // ----------------------------------------------------------------------------
  632. BOOL RBMoveBand(PRB prb, UINT iFrom, UINT iTo)
  633. {
  634. RBB rbbMove;
  635. int iShift;
  636. BOOL fCaptureChanged = (prb->iCapture == -1);
  637. if (iFrom != iTo)
  638. {
  639. rbbMove = *RBGETBAND(prb, iFrom);
  640. if (prb->iCapture == (int) iFrom)
  641. {
  642. prb->iCapture = (int) iTo;
  643. fCaptureChanged = TRUE;
  644. }
  645. iShift = (iFrom > iTo) ? -1 : 1;
  646. while (iFrom != iTo)
  647. {
  648. if (!fCaptureChanged && (prb->iCapture == (int) (iFrom + iShift)))
  649. {
  650. prb->iCapture = (int) iFrom;
  651. fCaptureChanged = TRUE;
  652. }
  653. *RBGETBAND(prb, iFrom) = *RBGETBAND(prb, iFrom + iShift);
  654. iFrom += iShift;
  655. }
  656. *RBGETBAND(prb, iTo) = rbbMove;
  657. return TRUE;
  658. }
  659. return(FALSE);
  660. }
  661. // ----------------------------------------------------------------------------
  662. //
  663. // RBRecalc
  664. //
  665. // recomputes bounding rects for all bands in given rebar
  666. //
  667. // ----------------------------------------------------------------------------
  668. UINT RBRecalc(PRB prb)
  669. {
  670. PRBB prbb = RBGETBAND(prb, 0);
  671. PRBB prbbWalk;
  672. UINT cHidden; // # of hidden guys we've seen in current row
  673. UINT cxRow;
  674. UINT cxMin;
  675. UINT i;
  676. UINT j;
  677. UINT k;
  678. UINT iFixed = 0xFFFF;
  679. int cy;
  680. int y;
  681. int x;
  682. UINT cxBar;
  683. RECT rc;
  684. HWND hwndSize;
  685. BOOL fNewLine = FALSE;
  686. BOOL fChanged;
  687. BOOL fVertical = (prb->ci.style & CCS_VERT);
  688. BOOL fBandBorders;
  689. int iBarWidth;
  690. if (!prb->cBands)
  691. return(0);
  692. if ((prb->ci.style & CCS_NORESIZE) || (prb->ci.style & CCS_NOPARENTALIGN))
  693. // size based on rebar window itself
  694. hwndSize = prb->ci.hwnd;
  695. else if (!(hwndSize = prb->ci.hwndParent))
  696. // size based on parent window -- if no parent window, bail now
  697. return(0);
  698. if (!prb->fRecalc) {
  699. // defer this recalc
  700. prb->fRecalcPending = TRUE;
  701. return 0;
  702. } else {
  703. prb->fRecalcPending = FALSE;
  704. }
  705. GetClientRect(hwndSize, &rc);
  706. iBarWidth = (fVertical ? (rc.bottom - rc.top) : (rc.right - rc.left));
  707. // this can happen because we adjust the client rect, but wedon't change
  708. // the getminmaxinfo.
  709. if (iBarWidth <= 0)
  710. iBarWidth = 1;
  711. cxBar = (UINT) iBarWidth;
  712. fBandBorders = (prb->ci.style & RBS_BANDBORDERS);
  713. for (i = 0; i < prb->cBands; i++) {
  714. prb->rbbList[i].cx = prb->rbbList[i].cxRequest;
  715. }
  716. y = 0;
  717. i = 0;
  718. // Main Loop -- loop until all bands are calculated
  719. while (i < prb->cBands)
  720. {
  721. TraceMsg(TF_REBAR, "RBRecalc: outer loop i=%d", i);
  722. if (fBandBorders && (y > 0))
  723. y += g_cyEdge;
  724. ReLoop:
  725. cxRow = 0;
  726. cxMin = 0;
  727. x = 0;
  728. cHidden = 0;
  729. // Row Loop -- loop until hard line break is found or soft line break
  730. // is necessary
  731. for (j = i, prbbWalk = prbb; j < prb->cBands; j++, prbbWalk++)
  732. {
  733. TraceMsg(TF_REBAR, "RBRecalc: inner loop j=%d", j);
  734. if (prbbWalk->fStyle & RBBS_HIDDEN) {
  735. ++cHidden;
  736. continue;
  737. }
  738. if (j > i + cHidden)
  739. {
  740. // not the first band in the row -- check for break style
  741. if ((prbbWalk->fStyle & RBBS_BREAK) && !(prbbWalk->fStyle & RBBS_FIXEDSIZE))
  742. break;
  743. if (fBandBorders)
  744. // add in space for vertical etch on palettized display
  745. cxMin += g_cxEdge;
  746. }
  747. if (prbbWalk->fStyle & RBBS_FIXEDSIZE)
  748. {
  749. // remember location of branding brick
  750. iFixed = j;
  751. // if this is the first band, the next band cannot have a forced break.
  752. if (i + cHidden == j) {
  753. // if the first index in the row (i) plus the number of hidden items (cHidden) leaves us at this band,
  754. // then it's the first visible in this row.
  755. PRBB prbbNextVis = RBBNextVisible(prb, prbbWalk);
  756. if (prbbNextVis && (prbbNextVis->fStyle & RBBS_BREAK)) {
  757. // can't do this unilaterally because on startup
  758. // some folks (net meeting) initialize it in reverse order
  759. // and we whack off this break bit incorrectly
  760. if (prb->fRedraw && IsWindowVisible(prb->ci.hwnd))
  761. prbbNextVis->fStyle &= ~RBBS_BREAK;
  762. }
  763. }
  764. prbbWalk->cx = prbbWalk->cxMin;
  765. }
  766. if (prbbWalk->cx < prbbWalk->cxMin)
  767. prbbWalk->cx = prbbWalk->cxMin;
  768. cxMin += prbbWalk->cxMin; // update running total of min widths
  769. // read the assert comment below
  770. if (j > i + cHidden)
  771. {
  772. // not the first band in row -- check for need to autobreak
  773. if (cxMin > cxBar)
  774. // autobreak here
  775. break;
  776. if (fBandBorders)
  777. // add in space for vertical etch on palettized display
  778. cxRow += g_cxEdge;
  779. }
  780. cxRow += prbbWalk->cx; // update running total of current widths
  781. }
  782. if (!i)
  783. {
  784. // first row -- handle proper placement of branding band
  785. if (iFixed == 0xFFFF)
  786. {
  787. // branding band not yet found; look in the remaining bands
  788. k = j;
  789. for ( ; j < prb->cBands; j++)
  790. {
  791. if (RBGETBAND(prb, j)->fStyle & RBBS_HIDDEN)
  792. continue;
  793. if (RBGETBAND(prb, j)->fStyle & RBBS_FIXEDSIZE)
  794. {
  795. // branding band found; move to 1st row and recompute
  796. ASSERT(j != k);
  797. RBMoveBand(prb, j, k);
  798. goto ReLoop;
  799. }
  800. }
  801. // no branding band found -- reset j and continue on
  802. j = k;
  803. }
  804. else
  805. // we have a branding band; move it to
  806. // the rightmost position in the row
  807. RBMoveBand(prb, iFixed, j - 1);
  808. TraceMsg(TF_REBAR, "RBRecalc: after brand i=%d", i);
  809. }
  810. // variant:
  811. // now the current row of bands is from i to j - 1
  812. // n.b. i (and some following bands) might be hidden
  813. // assert that j != i because then the above variant won't be true
  814. ASSERT(j != i); // BUGBUG RBBS_HIDDEN?
  815. if (cxRow > cxBar)
  816. {
  817. // bands are too long -- shrink bands from right to left
  818. for (k = i; k < j; k++)
  819. {
  820. prbbWalk--;
  821. if (prbbWalk->fStyle & RBBS_HIDDEN)
  822. continue;
  823. if (prbbWalk->cx > prbbWalk->cxMin)
  824. {
  825. cxRow -= prbbWalk->cx - prbbWalk->cxMin;
  826. prbbWalk->cx = prbbWalk->cxMin;
  827. if (cxRow <= cxBar)
  828. {
  829. prbbWalk->cx += cxBar - cxRow;
  830. break;
  831. }
  832. }
  833. }
  834. TraceMsg(TF_REBAR, "RBRecalc: after shrink i=%d", i);
  835. }
  836. else if (cxRow < cxBar)
  837. {
  838. // bands are too short -- grow rightmost non-minimized band
  839. for (k = j - 1; k >= i; k--)
  840. {
  841. ASSERT(k != (UINT)-1); // catch infinite loop
  842. prbbWalk--;
  843. if ((k == i) ||
  844. (!(prbbWalk->fStyle & (RBBS_HIDDEN | RBBS_FIXEDSIZE)) &&
  845. (prbbWalk->cx > prbb->cxMin)))
  846. {
  847. // the k == i check means we've made it to the first
  848. // band on this row and so he has to get the cx change
  849. if (prbbWalk->fStyle & RBBS_HIDDEN)
  850. {
  851. ASSERT(k == i);
  852. prbbWalk = RBBNextVisible(prb, prbbWalk);
  853. if (!prbbWalk)
  854. break;
  855. }
  856. prbbWalk->cx += cxBar - cxRow;
  857. break;
  858. }
  859. }
  860. TraceMsg(TF_REBAR, "RBRecalc: after grow i=%d", i);
  861. }
  862. // items from index i to index j-1 (inclusive) WILL fit on one line
  863. cy = RBGetLineHeight(prb, i, j - 1);
  864. fChanged = FALSE; // set if any bands on current row changed position
  865. for ( ; i < j; i++, prbb++)
  866. {
  867. if (prbb->fStyle & RBBS_HIDDEN)
  868. continue;
  869. // go through row of bands, updating positions and heights,
  870. // invalidating as needed
  871. if ((prbb->y != y) || (prbb->x != x) || (prbb->cy != cy))
  872. {
  873. TraceMsg(TF_REBAR, "RBRecalc: invalidate i=%d", RBBANDTOINDEX(prb, prbb));
  874. fChanged = TRUE;
  875. rc.left = min(prbb->x, x);
  876. rc.top = min(prbb->y, y);
  877. rc.right = cxBar;
  878. rc.bottom = max(prbb->y + prbb->cy, y + cy);
  879. if (fBandBorders)
  880. {
  881. // acount for etch line that will need to move
  882. rc.left -= g_cxEdge;
  883. rc.bottom += g_cyEdge/2;
  884. }
  885. RBInvalidateRect(prb, &rc);
  886. }
  887. prbb->x = x;
  888. prbb->y = y;
  889. prbb->cy = cy;
  890. x += RBBANDWIDTH(prb, prbb);
  891. }
  892. // i and prbb now refer to the first band in the next row of bands
  893. y += cy;
  894. }
  895. prb->cy = y;
  896. return(y);
  897. }
  898. // ----------------------------------------------------------------------------
  899. //
  900. // RBResize
  901. //
  902. // recomputes bounding rects for all bands and then resizes rebar and children
  903. // based on these rects
  904. //
  905. // ----------------------------------------------------------------------------
  906. void RBResizeNow(PRB prb)
  907. {
  908. RECT rc;
  909. BOOL bMirroredWnd=(prb->ci.dwExStyle&RTL_MIRRORED_WINDOW);
  910. if (!prb || !prb->ci.hwndParent)
  911. return;
  912. GetWindowRect(prb->ci.hwnd, &rc);
  913. //
  914. // If this is a mirrored window, we don't won't to refect the
  915. // coordinates since they are coming from the screen coord
  916. // which they are not mirrored. [samera]
  917. //
  918. if (bMirroredWnd)
  919. MapRectInRTLMirroredWindow(&rc, prb->ci.hwndParent);
  920. else
  921. MapWindowPoints(HWND_DESKTOP, prb->ci.hwndParent, (LPPOINT)&rc, 2);
  922. RBResizeChildren(prb);
  923. NewSize(prb->ci.hwnd, prb->cy, prb->ci.style, rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc));
  924. if (prb->fResizeNotify)
  925. CCSendNotify(&prb->ci, RBN_HEIGHTCHANGE, NULL);
  926. prb->fResizeNotify = FALSE;
  927. prb->fResizePending = FALSE;
  928. }
  929. void RBResize(PRB prb, BOOL fForceHeightChange)
  930. {
  931. UINT cy;
  932. StartOver:
  933. // lots of the code relies on having cy calculated synchronously with RBResize,
  934. // but we're going to delay the actual changing of the window
  935. cy = prb->cy;
  936. if (prb->fResizing)
  937. {
  938. prb->fResizeRecursed = TRUE;
  939. return;
  940. }
  941. prb->fResizing = TRUE;
  942. RBRecalc(prb);
  943. // true overrides always
  944. if (fForceHeightChange || (cy != prb->cy))
  945. prb->fResizeNotify = TRUE;
  946. if (prb->fRedraw) {
  947. RBResizeNow(prb);
  948. } else
  949. prb->fResizePending = TRUE;
  950. prb->fResizing = FALSE;
  951. // we do this to avoid infinite loop... RBResize can cause NewSize which causes
  952. // a notify in which the parent sizes us, which causes us to loop.
  953. // if the parent does any message pumping during the NewSize, we're in a loop
  954. if (prb->fResizeRecursed) {
  955. prb->fResizeRecursed = FALSE;
  956. fForceHeightChange = FALSE;
  957. goto StartOver;
  958. }
  959. }
  960. void RBSetRecalc(PRB prb, BOOL fRecalc)
  961. {
  962. prb->fRecalc = fRecalc;
  963. if (fRecalc) {
  964. if (prb->fRecalcPending)
  965. RBRecalc(prb);
  966. }
  967. }
  968. BOOL RBSetRedraw(PRB prb, BOOL fRedraw)
  969. {
  970. BOOL fOld = prb->fRedraw;
  971. if (prb) {
  972. prb->fRedraw = BOOLIFY(fRedraw);
  973. if (fRedraw) {
  974. // save off prb->fRefreshPending since this can
  975. // get changed by call to RBResizeNow
  976. BOOL fRefreshPending = prb->fRefreshPending;
  977. if (prb->fResizePending)
  978. RBResizeNow(prb);
  979. if (fRefreshPending)
  980. RBInvalidateRect(prb, NULL);
  981. }
  982. }
  983. return fOld;
  984. }
  985. BOOL RBAfterSetFont(PRB prb)
  986. {
  987. TEXTMETRIC tm;
  988. BOOL fChange = FALSE;
  989. UINT i;
  990. HFONT hOldFont;
  991. HDC hdc = GetDC(prb->ci.hwnd);
  992. if (!hdc)
  993. return FALSE;
  994. hOldFont = SelectObject(hdc, prb->hFont);
  995. GetTextMetrics(hdc, &tm);
  996. if (prb->cyFont != (UINT) tm.tmHeight)
  997. {
  998. prb->cyFont = tm.tmHeight;
  999. fChange = TRUE;
  1000. }
  1001. // adjust bands
  1002. for (i = 0; i < prb->cBands; i++)
  1003. {
  1004. if (RBGETBAND(prb, i)->fStyle & RBBS_HIDDEN)
  1005. continue;
  1006. fChange |= RBBCalcTextExtent(prb, RBGETBAND(prb, i), hdc);
  1007. }
  1008. SelectObject(hdc, hOldFont);
  1009. ReleaseDC(prb->ci.hwnd, hdc);
  1010. if (fChange)
  1011. {
  1012. RBResize(prb, FALSE);
  1013. // invalidate, o.w. title doesn't redraw 1st time after font growth
  1014. RBInvalidateRect(prb, NULL);
  1015. }
  1016. return TRUE;
  1017. }
  1018. BOOL RBOnSetFont(PRB prb, HFONT hFont)
  1019. {
  1020. if (prb->fFontCreated) {
  1021. DeleteObject(prb->hFont);
  1022. }
  1023. prb->hFont = hFont;
  1024. prb->fFontCreated = FALSE;
  1025. if (!prb->hFont)
  1026. RBSetFont(prb, 0);
  1027. else
  1028. return RBAfterSetFont(prb);
  1029. return TRUE;
  1030. }
  1031. // ----------------------------------------------------------------------------
  1032. //
  1033. // RBSetFont
  1034. //
  1035. // sets the rebar band title font to the current system-wide caption font
  1036. //
  1037. // ----------------------------------------------------------------------------
  1038. BOOL RBSetFont(PRB prb, WPARAM wParam)
  1039. {
  1040. NONCLIENTMETRICS ncm;
  1041. HFONT hOldFont;
  1042. if ((wParam != 0) && (wParam != SPI_SETNONCLIENTMETRICS))
  1043. return(FALSE);
  1044. ncm.cbSize = sizeof(NONCLIENTMETRICS);
  1045. if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0))
  1046. return(FALSE);
  1047. hOldFont = prb->hFont;
  1048. ncm.lfCaptionFont.lfWeight = FW_NORMAL;
  1049. if (!(prb->hFont = CreateFontIndirect(&ncm.lfCaptionFont)))
  1050. {
  1051. prb->hFont = hOldFont;
  1052. return(FALSE);
  1053. }
  1054. prb->fFontCreated = TRUE;
  1055. if (hOldFont)
  1056. DeleteObject(hOldFont);
  1057. return RBAfterSetFont(prb);
  1058. }
  1059. // ----------------------------------------------------------------------------
  1060. //
  1061. // Draws a horizontal or vertical dotted line from the given (x,y) location
  1062. // for the given length (c). (From TReeView's TV_DrawDottedLine)
  1063. //
  1064. // ----------------------------------------------------------------------------
  1065. void RBVertMungeGripperRect(PRB prb, LPRECT lprc)
  1066. {
  1067. if (RB_ISVERTICALGRIPPER(prb)) {
  1068. OffsetRect(lprc, -lprc->left + lprc->top, -lprc->top + lprc->left);
  1069. lprc->bottom -= g_cyEdge;
  1070. } else {
  1071. FlipRect(lprc);
  1072. }
  1073. }
  1074. void RBDrawChevron(PRB prb, PRBB prbb, HDC hdc)
  1075. {
  1076. RECT rc;
  1077. DWORD dwFlags = prbb->wChevState | DCHF_HORIZONTAL | DCHF_TRANSPARENT;
  1078. CopyRect(&rc, &prbb->rcChevron);
  1079. if (RB_ISVERT(prb))
  1080. FlipRect(&rc);
  1081. else
  1082. dwFlags |= DCHF_TOPALIGN;
  1083. DrawChevron(hdc, &rc, dwFlags);
  1084. }
  1085. void RBUpdateChevronState(PRB prb, PRBB prbb, WORD wControlState)
  1086. {
  1087. if (!prb || !prbb)
  1088. return;
  1089. // if no change in state, bail
  1090. if (!(wControlState ^ prbb->wChevState))
  1091. return;
  1092. prbb->wChevState = wControlState;
  1093. // if active (pushed or hottracked)
  1094. if (!(wControlState & DCHF_INACTIVE)) {
  1095. // then we're now the hot band
  1096. prb->prbbHot = prbb;
  1097. }
  1098. // else if we were the hot band then clear
  1099. else if (prbb == prb->prbbHot) {
  1100. prb->prbbHot = NULL;
  1101. }
  1102. // clear background & repaint
  1103. RBInvalidateRect(prb, &prbb->rcChevron);
  1104. UpdateWindow(prb->ci.hwnd);
  1105. }
  1106. // ----------------------------------------------------------------------------
  1107. //
  1108. // RBDrawBand
  1109. //
  1110. // draws the title icon and title text of the given band into the given DC;
  1111. // also the band's chevron
  1112. //
  1113. // ----------------------------------------------------------------------------
  1114. void RBDrawBand(PRB prb, PRBB prbb, HDC hdc)
  1115. {
  1116. int xStart, yCenter;
  1117. COLORREF clrBackSave, clrForeSave;
  1118. int iModeSave;
  1119. BOOL fVertical = RB_ISVERT(prb);
  1120. BOOL fDrawHorizontal = (!fVertical || RB_ISVERTICALGRIPPER(prb));
  1121. NMCUSTOMDRAW nmcd;
  1122. LRESULT dwRet;
  1123. if (prbb->fStyle & RBBS_HIDDEN) {
  1124. ASSERT(0);
  1125. return;
  1126. }
  1127. clrForeSave = SetTextColor(hdc, RBB_GetTextColor(prb, prbb));
  1128. clrBackSave = SetBkColor(hdc, RBB_GetBkColor(prb, prbb));
  1129. if (prbb->hbmBack)
  1130. iModeSave = SetBkMode(hdc, TRANSPARENT);
  1131. nmcd.hdc = hdc;
  1132. nmcd.dwItemSpec = prbb->wID;
  1133. nmcd.uItemState = 0;
  1134. nmcd.lItemlParam = prbb->lParam;
  1135. nmcd.rc.top = prbb->y;
  1136. nmcd.rc.left = prbb->x;
  1137. nmcd.rc.bottom = nmcd.rc.top + prbb->cy;
  1138. nmcd.rc.right = nmcd.rc.left + RBBHEADERWIDTH(prbb);
  1139. if (prb->ci.style & CCS_VERT)
  1140. {
  1141. FlipRect(&nmcd.rc);
  1142. }
  1143. #ifdef KEYBOARDCUES
  1144. #if 0
  1145. // BUGBUG: Custom draw stuff for UISTATE (stephstm)
  1146. if (CCGetUIState(&(prb->ci), KC_TBD))
  1147. nmcd.uItemState |= CDIS_SHOWKEYBOARDCUES;
  1148. #endif
  1149. #endif
  1150. dwRet = CICustomDrawNotify(&prb->ci, CDDS_ITEMPREPAINT, &nmcd);
  1151. if (!(dwRet & CDRF_SKIPDEFAULT))
  1152. {
  1153. int cy;
  1154. if (RB_ISVERTICALGRIPPER(prb)) {
  1155. cy = RBBHEADERWIDTH(prbb);
  1156. yCenter = prbb->x + (cy / 2);
  1157. } else {
  1158. cy = prbb->cy;
  1159. yCenter = prbb->y + (cy / 2);
  1160. }
  1161. xStart = prbb->x;
  1162. if (RBShouldDrawGripper(prb, prbb))
  1163. {
  1164. RECT rc;
  1165. int c;
  1166. int dy;
  1167. c = 3 * g_cyBorder;
  1168. xStart += 2 * g_cxBorder;
  1169. dy = g_cxEdge;
  1170. SetRect(&rc, xStart, prbb->y + dy, xStart + c, prbb->y + cy - dy);
  1171. if (fVertical)
  1172. {
  1173. RBVertMungeGripperRect(prb, &rc);
  1174. if (RB_ISVERTICALGRIPPER(prb))
  1175. xStart = rc.left;
  1176. }
  1177. CCDrawEdge(hdc, &rc, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE, &(prb->clrsc));
  1178. xStart += c;
  1179. }
  1180. xStart += 2 * (fVertical ? g_cyEdge : g_cxEdge);
  1181. if (prbb->iImage != -1)
  1182. {
  1183. UINT yStart;
  1184. IMAGELISTDRAWPARAMS imldp = {0};
  1185. yStart = yCenter - ((!fDrawHorizontal ? prb->cxImage : prb->cyImage) / 2);
  1186. imldp.cbSize = sizeof(imldp);
  1187. imldp.himl = prb->himl;
  1188. imldp.i = prbb->iImage;
  1189. imldp.hdcDst = hdc;
  1190. imldp.x = (!fDrawHorizontal ? yStart : xStart);
  1191. imldp.y = (!fDrawHorizontal ? xStart : yStart);
  1192. imldp.rgbBk = CLR_DEFAULT;
  1193. imldp.rgbFg = CLR_DEFAULT;
  1194. imldp.fStyle = ILD_TRANSPARENT;
  1195. ImageList_DrawIndirect(&imldp);
  1196. xStart += (fDrawHorizontal ? (prb->cxImage + g_cxEdge) : (prb->cyImage + g_cyEdge));
  1197. }
  1198. if (RBSHOWTEXT(prbb))
  1199. {
  1200. HFONT hFontSave = SelectObject(hdc, prb->hFont);
  1201. RECT rcText;
  1202. rcText.left = fDrawHorizontal ? xStart : yCenter - (prbb->cxText / 2);
  1203. rcText.top = fDrawHorizontal ? yCenter - (prb->cyFont / 2) : xStart;
  1204. if (fDrawHorizontal)
  1205. rcText.top -= 1; // fudge
  1206. rcText.right = rcText.left + prbb->cxText;
  1207. rcText.bottom = rcText.top + prb->cyFont;
  1208. // for clients >= v5, we draw text with prefix processing (& underlines next char)
  1209. if (prb->ci.iVersion >= 5)
  1210. {
  1211. UINT uFormat=0;
  1212. #ifdef KEYBOARDCUES
  1213. if (CCGetUIState(&(prb->ci)) & UISF_HIDEACCEL)
  1214. uFormat= DT_HIDEPREFIX;
  1215. #endif
  1216. DrawText(hdc, prbb->lpText, lstrlen(prbb->lpText), &rcText, uFormat);
  1217. }
  1218. else
  1219. TextOut(hdc, rcText.left, rcText.top, prbb->lpText, lstrlen(prbb->lpText));
  1220. SelectObject(hdc, hFontSave);
  1221. }
  1222. // maybe draw chevron
  1223. if (RBBUSECHEVRON(prb, prbb) && prbb->fChevron)
  1224. RBDrawChevron(prb, prbb, hdc);
  1225. }
  1226. if (dwRet & CDRF_NOTIFYPOSTPAINT)
  1227. CICustomDrawNotify(&prb->ci, CDDS_ITEMPOSTPAINT, &nmcd);
  1228. if (prbb->hbmBack)
  1229. SetBkMode(hdc, iModeSave);
  1230. SetTextColor(hdc, clrForeSave);
  1231. SetBkColor(hdc, clrBackSave);
  1232. }
  1233. // ----------------------------------------------------------------------------
  1234. //
  1235. // RBPaint
  1236. //
  1237. // processes WM_PAINT message
  1238. //
  1239. // ----------------------------------------------------------------------------
  1240. void RBPaint(PRB prb, HDC hdcIn)
  1241. {
  1242. HDC hdc = hdcIn;
  1243. PAINTSTRUCT ps;
  1244. UINT i;
  1245. NMCUSTOMDRAW nmcd;
  1246. if (!hdcIn)
  1247. hdc = BeginPaint(prb->ci.hwnd, &ps);
  1248. else
  1249. GetClientRect(prb->ci.hwnd, &ps.rcPaint);
  1250. nmcd.hdc = hdc;
  1251. nmcd.uItemState = 0;
  1252. nmcd.lItemlParam = 0;
  1253. nmcd.rc = ps.rcPaint;
  1254. prb->ci.dwCustom = CICustomDrawNotify(&prb->ci, CDDS_PREPAINT, &nmcd);
  1255. if (!(prb->ci.dwCustom & CDRF_SKIPDEFAULT))
  1256. {
  1257. for (i = 0; i < prb->cBands; i++) {
  1258. if (RBGETBAND(prb, i)->fStyle & RBBS_HIDDEN)
  1259. continue;
  1260. RBDrawBand(prb, RBGETBAND(prb, i), hdc);
  1261. }
  1262. }
  1263. if (prb->ci.dwCustom & CDRF_NOTIFYPOSTPAINT)
  1264. CICustomDrawNotify(&prb->ci, CDDS_POSTPAINT, &nmcd);
  1265. if (!hdcIn)
  1266. EndPaint(prb->ci.hwnd, &ps);
  1267. }
  1268. // ----------------------------------------------------------------------------
  1269. //
  1270. // RBTileBlt
  1271. //
  1272. // Fills the given rectangle with the rebar's background bitmap, tiling if
  1273. // necessary
  1274. //
  1275. // ----------------------------------------------------------------------------
  1276. void RBTileBlt(PRB prb, PRBB prbb, UINT x, UINT y, UINT cx, UINT cy, HDC hdcDst, HDC hdcSrc)
  1277. {
  1278. UINT xOff = 0;
  1279. UINT yOff = 0;
  1280. BOOL fxTile, fyTile;
  1281. int cxPart, cyPart;
  1282. int iPixelOffset = 0;
  1283. #ifndef WINNT
  1284. // On Win98 BiDi, Bitblt has off-by-one bug in mirroring
  1285. if(IS_DC_RTL_MIRRORED(hdcSrc))
  1286. {
  1287. iPixelOffset = 1;
  1288. }
  1289. #endif // WINNT
  1290. if (!(prbb->fStyle & RBBS_FIXEDBMP))
  1291. {
  1292. if (prb->ci.style & CCS_VERT)
  1293. {
  1294. xOff = -prbb->y;
  1295. yOff = -prbb->x;
  1296. }
  1297. else
  1298. {
  1299. xOff = -prbb->x;
  1300. yOff = -prbb->y;
  1301. }
  1302. }
  1303. xOff += x;
  1304. if (xOff >= prbb->cxBmp)
  1305. xOff %= prbb->cxBmp;
  1306. yOff += y;
  1307. if (yOff >= prbb->cyBmp)
  1308. yOff %= prbb->cyBmp;
  1309. ReCheck:
  1310. fxTile = ((xOff + cx) > prbb->cxBmp);
  1311. fyTile = ((yOff + cy) > prbb->cyBmp);
  1312. if (!fxTile && !fyTile)
  1313. {
  1314. // no tiling needed -- blt and leave
  1315. BitBlt(hdcDst, x , y, cx, cy, hdcSrc, xOff + iPixelOffset, yOff, SRCCOPY);
  1316. return;
  1317. }
  1318. if (!fxTile)
  1319. {
  1320. // vertically tile
  1321. cyPart = prbb->cyBmp - yOff;
  1322. BitBlt(hdcDst, x, y, cx, cyPart, hdcSrc, xOff + iPixelOffset, yOff, SRCCOPY);
  1323. y += cyPart;
  1324. cy -= cyPart;
  1325. yOff = 0;
  1326. goto ReCheck;
  1327. }
  1328. if (!fyTile)
  1329. {
  1330. // horizontally tile
  1331. cxPart = prbb->cxBmp - xOff;
  1332. BitBlt(hdcDst, x, y, cxPart, cy, hdcSrc, xOff + iPixelOffset, yOff, SRCCOPY);
  1333. x += cxPart;
  1334. cx -= cxPart;
  1335. xOff = 0;
  1336. goto ReCheck;
  1337. }
  1338. // tile both ways
  1339. cyPart = prbb->cyBmp - yOff;
  1340. RBTileBlt(prb, prbb, x, y, cx, cyPart, hdcDst, hdcSrc);
  1341. y += cyPart;
  1342. cy -= cyPart;
  1343. yOff = 0;
  1344. goto ReCheck;
  1345. }
  1346. // this is using virtual coordinate space (internal always horizontal)
  1347. int _RBHitTest(PRB prb, LPRBHITTESTINFO prbht, int x, int y)
  1348. {
  1349. BOOL fVert = (prb->ci.style & CCS_VERT);
  1350. int i;
  1351. PRBB prbb = RBGETBAND(prb, 0);
  1352. int cx;
  1353. RBHITTESTINFO rbht;
  1354. if (!prbht)
  1355. prbht = &rbht;
  1356. for (i = 0; i < (int) prb->cBands; i++, prbb++)
  1357. {
  1358. if (prbb->fStyle & RBBS_HIDDEN)
  1359. continue;
  1360. if ((x >= prbb->x) && (y >= prbb->y) &&
  1361. (x <= (prbb->x + prbb->cx)) && (y <= (prbb->y + prbb->cy)))
  1362. {
  1363. cx = RBBHEADERWIDTH(prbb);
  1364. if (x <= (int) (prbb->x + cx))
  1365. {
  1366. prbht->flags = RBHT_CAPTION;
  1367. if (RB_ISVERTICALGRIPPER(prb)) {
  1368. if (y - prbb->y < RB_GRABWIDTH)
  1369. prbht->flags = RBHT_GRABBER;
  1370. } else {
  1371. cx = RB_GRABWIDTH * (fVert ? g_cyBorder : g_cxBorder);
  1372. if (RBShouldDrawGripper(prb, RBGETBAND(prb, i)) &&
  1373. (x <= (int) (prbb->x + cx)))
  1374. prbht->flags = RBHT_GRABBER;
  1375. }
  1376. }
  1377. else
  1378. {
  1379. POINT pt;
  1380. pt.x = x;
  1381. pt.y = y;
  1382. if (RBBUSECHEVRON(prb, prbb) && prbb->fChevron && PtInRect(&prbb->rcChevron, pt))
  1383. prbht->flags = RBHT_CHEVRON;
  1384. else
  1385. prbht->flags = RBHT_CLIENT;
  1386. }
  1387. prbht->iBand = i;
  1388. return(i);
  1389. break;
  1390. }
  1391. }
  1392. prbht->flags = RBHT_NOWHERE;
  1393. prbht->iBand = -1;
  1394. return(-1);
  1395. }
  1396. // ----------------------------------------------------------------------------
  1397. //
  1398. // RBHitTest
  1399. //
  1400. // returns the index to the band that the given point lies in, or -1 if outside
  1401. // of all bands. Also, sets flags to indicate which part of the band the
  1402. // point lies in.
  1403. //
  1404. // ----------------------------------------------------------------------------
  1405. int RBHitTest(PRB prb, LPRBHITTESTINFO prbht)
  1406. {
  1407. BOOL fVert = (prb->ci.style & CCS_VERT);
  1408. POINT pt;
  1409. if (fVert)
  1410. {
  1411. pt.x = prbht->pt.y;
  1412. pt.y = prbht->pt.x;
  1413. }
  1414. else
  1415. pt = prbht->pt;
  1416. return _RBHitTest(prb, prbht, pt.x, pt.y);
  1417. }
  1418. // ----------------------------------------------------------------------------
  1419. //
  1420. // RBEraseBkgnd
  1421. //
  1422. // processes WM_ERASEBKGND message by drawing band borders, if necessary, and
  1423. // filling in the rebar bands with their background color
  1424. //
  1425. // ----------------------------------------------------------------------------
  1426. BOOL RBEraseBkgnd(PRB prb, HDC hdc, int iBand)
  1427. {
  1428. BOOL fVertical = (prb->ci.style & CCS_VERT);
  1429. NMCUSTOMDRAW nmcd;
  1430. LRESULT dwItemRet;
  1431. BOOL fBandBorders;
  1432. RECT rcClient;
  1433. HDC hdcMem = NULL;
  1434. UINT i;
  1435. PRBB prbb = RBGETBAND(prb, 0);
  1436. nmcd.hdc = hdc;
  1437. nmcd.uItemState = 0;
  1438. nmcd.lItemlParam = 0;
  1439. prb->ci.dwCustom = CICustomDrawNotify(&prb->ci, CDDS_PREERASE, &nmcd);
  1440. if (!(prb->ci.dwCustom & CDRF_SKIPDEFAULT))
  1441. {
  1442. COLORREF clrBk;
  1443. fBandBorders = (prb->ci.style & RBS_BANDBORDERS);
  1444. GetClientRect(prb->ci.hwnd, &rcClient);
  1445. clrBk = RB_GetBkColor(prb);
  1446. if (clrBk != CLR_NONE) {
  1447. FillRectClr(hdc, &rcClient, clrBk);
  1448. }
  1449. for (i = 0; i < prb->cBands; i++, prbb++)
  1450. {
  1451. if (prbb->fStyle & RBBS_HIDDEN)
  1452. continue;
  1453. if (fVertical)
  1454. SetRect(&nmcd.rc, prbb->y, prbb->x, prbb->y + prbb->cy, prbb->x + prbb->cx);
  1455. else
  1456. SetRect(&nmcd.rc, prbb->x, prbb->y, prbb->x + prbb->cx, prbb->y + prbb->cy);
  1457. if (fBandBorders)
  1458. {
  1459. if (prbb->x)
  1460. {
  1461. // draw etch between bands on same row
  1462. if (fVertical)
  1463. {
  1464. nmcd.rc.right += g_cxEdge / 2;
  1465. nmcd.rc.top -= g_cyEdge;
  1466. CCDrawEdge(hdc, &nmcd.rc, EDGE_ETCHED, BF_TOP, &(prb->clrsc));
  1467. nmcd.rc.right -= g_cxEdge / 2;
  1468. nmcd.rc.top += g_cyEdge;
  1469. }
  1470. else
  1471. {
  1472. nmcd.rc.bottom += g_cyEdge / 2;
  1473. nmcd.rc.left -= g_cxEdge;
  1474. CCDrawEdge(hdc, &nmcd.rc, EDGE_ETCHED, BF_LEFT, &(prb->clrsc));
  1475. nmcd.rc.bottom -= g_cyEdge / 2;
  1476. nmcd.rc.left += g_cxEdge;
  1477. }
  1478. }
  1479. else
  1480. {
  1481. // draw etch between rows
  1482. if (fVertical)
  1483. {
  1484. rcClient.right = prbb->y + prbb->cy + g_cxEdge;
  1485. CCDrawEdge(hdc, &rcClient, EDGE_ETCHED, BF_RIGHT, &(prb->clrsc));
  1486. }
  1487. else
  1488. {
  1489. rcClient.bottom = prbb->y + prbb->cy + g_cyEdge;
  1490. CCDrawEdge(hdc, &rcClient, EDGE_ETCHED, BF_BOTTOM, &(prb->clrsc));
  1491. }
  1492. }
  1493. }
  1494. nmcd.dwItemSpec = prbb->wID;
  1495. nmcd.uItemState = 0;
  1496. dwItemRet = CICustomDrawNotify(&prb->ci, CDDS_ITEMPREERASE, &nmcd);
  1497. if (!(dwItemRet & CDRF_SKIPDEFAULT))
  1498. {
  1499. if (prbb->hbmBack)
  1500. {
  1501. if (!hdcMem)
  1502. {
  1503. if (!(hdcMem = CreateCompatibleDC(hdc)))
  1504. continue;
  1505. RBRealize(prb, hdc, TRUE, FALSE);
  1506. }
  1507. SelectObject(hdcMem, prbb->hbmBack);
  1508. RBTileBlt(prb, prbb, nmcd.rc.left, nmcd.rc.top, nmcd.rc.right - nmcd.rc.left,
  1509. nmcd.rc.bottom - nmcd.rc.top, hdc, hdcMem);
  1510. }
  1511. else
  1512. {
  1513. // if the color for this band is the same as the
  1514. // rebar's default background color, then we
  1515. // don't need to paint this specially
  1516. COLORREF clr = RBB_GetBkColor(prb, prbb);
  1517. if (clr != RB_GetBkColor(prb)) {
  1518. FillRectClr(hdc, &nmcd.rc, clr);
  1519. }
  1520. }
  1521. }
  1522. if (dwItemRet & CDRF_NOTIFYPOSTERASE)
  1523. CICustomDrawNotify(&prb->ci, CDDS_ITEMPOSTERASE, &nmcd);
  1524. }
  1525. if (hdcMem)
  1526. {
  1527. DeleteDC(hdcMem);
  1528. }
  1529. }
  1530. if (prb->ci.dwCustom & CDRF_NOTIFYPOSTERASE)
  1531. {
  1532. nmcd.uItemState = 0;
  1533. nmcd.dwItemSpec = 0;
  1534. nmcd.lItemlParam = 0;
  1535. CICustomDrawNotify(&prb->ci, CDDS_POSTERASE, &nmcd);
  1536. }
  1537. return(TRUE);
  1538. }
  1539. // ----------------------------------------------------------------------------
  1540. //
  1541. // RBGetBarInfo
  1542. //
  1543. // retrieves the indicated values from the rebar's internal structure
  1544. //
  1545. // ----------------------------------------------------------------------------
  1546. BOOL RBGetBarInfo(PRB prb, LPREBARINFO lprbi)
  1547. {
  1548. if (!prb || (lprbi->cbSize != sizeof(REBARINFO)))
  1549. return(FALSE);
  1550. if (lprbi->fMask & RBIM_IMAGELIST)
  1551. lprbi->himl = prb->himl;
  1552. return(TRUE);
  1553. }
  1554. // ----------------------------------------------------------------------------
  1555. //
  1556. // RBSetBarInfo
  1557. //
  1558. // sets the indicated values in the rebar's internal structure, recalculating
  1559. // and refreshing as needed
  1560. //
  1561. // ----------------------------------------------------------------------------
  1562. BOOL RBSetBarInfo(PRB prb, LPREBARINFO lprbi)
  1563. {
  1564. if (!prb || (lprbi->cbSize != sizeof(REBARINFO)))
  1565. return(FALSE);
  1566. if (lprbi->fMask & RBIM_IMAGELIST)
  1567. {
  1568. HIMAGELIST himl = prb->himl;
  1569. UINT cxOld, cyOld;
  1570. //todo:validate lprbi->himl
  1571. prb->himl = lprbi->himl;
  1572. cxOld = prb->cxImage;
  1573. cyOld = prb->cyImage;
  1574. ImageList_GetIconSize(prb->himl, (LPINT)&prb->cxImage, (LPINT)&prb->cyImage);
  1575. if ((prb->cxImage != cxOld) || (prb->cyImage != cyOld))
  1576. {
  1577. UINT i;
  1578. for (i = 0; i < prb->cBands; i++) {
  1579. if (RBGETBAND(prb, i)->fStyle & RBBS_HIDDEN)
  1580. continue;
  1581. RBBCalcMinWidth(prb, RBGETBAND(prb, i));
  1582. }
  1583. RBResize(prb, FALSE);
  1584. }
  1585. else
  1586. RBInvalidateRect(prb, NULL);
  1587. lprbi->himl = himl;
  1588. }
  1589. return(TRUE);
  1590. }
  1591. // ----------------------------------------------------------------------------
  1592. //
  1593. // RBGetBandInfo
  1594. //
  1595. // retrieves the indicated values from the specified band's internal structure
  1596. //
  1597. // ----------------------------------------------------------------------------
  1598. BOOL RBGetBandInfo(PRB prb, UINT uBand, LPREBARBANDINFO lprbbi)
  1599. {
  1600. PRBB prbb;
  1601. if (!prb || (!RB_ISVALIDINDEX(prb, uBand)) || (lprbbi->cbSize > SIZEOF(REBARBANDINFO)))
  1602. return(FALSE);
  1603. prbb = RBGETBAND(prb, uBand);
  1604. if (lprbbi->fMask & RBBIM_SIZE) {
  1605. if (prbb->fStyle & RBBS_FIXEDSIZE)
  1606. lprbbi->cx = prbb->cx;
  1607. else
  1608. lprbbi->cx = prbb->cxRequest;
  1609. }
  1610. if (lprbbi->fMask & RBBIM_HEADERSIZE)
  1611. lprbbi->cxHeader = RBBHEADERWIDTH(prbb);
  1612. if (lprbbi->fMask & RBBIM_IDEALSIZE)
  1613. // HACKHACK: (tjgreen) Subtract the offset we added in SetBandInfo (see
  1614. // comments there).
  1615. lprbbi->cxIdeal = prbb->cxIdeal ? prbb->cxIdeal - CX_OFFSET : 0;
  1616. if (lprbbi->fMask & RBBIM_STYLE)
  1617. lprbbi->fStyle = prbb->fStyle;
  1618. if (lprbbi->fMask & RBBIM_COLORS)
  1619. {
  1620. lprbbi->clrFore = RBB_GetTextColor_External(prb, prbb);
  1621. lprbbi->clrBack = RBB_GetBkColor_External(prb, prbb);
  1622. }
  1623. if (lprbbi->fMask & RBBIM_TEXT)
  1624. {
  1625. UINT cch = prbb->lpText ? lstrlen(prbb->lpText) : 0;
  1626. if (!lprbbi->cch || !lprbbi->lpText || (lprbbi->cch <= cch))
  1627. lprbbi->cch = cch + 1;
  1628. else if (prbb->lpText)
  1629. lstrcpy(lprbbi->lpText, prbb->lpText);
  1630. else
  1631. // no text -- so just make it an empty string
  1632. lprbbi->lpText[0] = 0;
  1633. }
  1634. if (lprbbi->fMask & RBBIM_IMAGE)
  1635. lprbbi->iImage = prbb->iImage;
  1636. if (lprbbi->fMask & RBBIM_CHILD)
  1637. lprbbi->hwndChild = prbb->hwndChild;
  1638. if (lprbbi->fMask & RBBIM_CHILDSIZE)
  1639. {
  1640. // HACKHACK: (tjgreen) Subtract the offset we added in SetBandInfo (see
  1641. // comments there).
  1642. lprbbi->cxMinChild = prbb->cxMinChild ? prbb->cxMinChild - CX_OFFSET : 0;
  1643. lprbbi->cyMinChild = prbb->cyMinChild;
  1644. if (prbb->fStyle & RBBS_VARIABLEHEIGHT) {
  1645. lprbbi->cyIntegral = prbb->cyIntegral;
  1646. lprbbi->cyMaxChild = prbb->cyMaxChild;
  1647. lprbbi->cyChild = prbb->cyChild;
  1648. }
  1649. }
  1650. if (lprbbi->fMask & RBBIM_BACKGROUND)
  1651. lprbbi->hbmBack = prbb->hbmBack;
  1652. if (lprbbi->fMask & RBBIM_ID)
  1653. lprbbi->wID = prbb->wID;
  1654. if (lprbbi->fMask & RBBIM_LPARAM)
  1655. lprbbi->lParam = prbb->lParam;
  1656. return(TRUE);
  1657. }
  1658. BOOL RBValidateBandInfo(LPREBARBANDINFO *pprbbi, LPREBARBANDINFO prbbi)
  1659. {
  1660. BOOL fRet = ((*pprbbi)->cbSize == sizeof(REBARBANDINFO));
  1661. if (!fRet) {
  1662. if ((*pprbbi)->cbSize < SIZEOF(REBARBANDINFO)) {
  1663. hmemcpy(prbbi, (*pprbbi), (*pprbbi)->cbSize);
  1664. (*pprbbi) = prbbi;
  1665. prbbi->cbSize = SIZEOF(REBARBANDINFO);
  1666. fRet = TRUE;
  1667. }
  1668. }
  1669. return fRet;
  1670. }
  1671. // ----------------------------------------------------------------------------
  1672. //
  1673. // RBSetBandInfo
  1674. //
  1675. // sets the indicated values in the specified band's internal structure,
  1676. // recalculating and refreshing as needed
  1677. //
  1678. // ----------------------------------------------------------------------------
  1679. BOOL RBSetBandInfo(PRB prb, UINT uBand, LPREBARBANDINFO lprbbi, BOOL fAllowRecalc)
  1680. {
  1681. PRBB prbb;
  1682. BOOL fRefresh = FALSE;
  1683. BOOL fRecalc = FALSE;
  1684. BOOL fRecalcMin = FALSE;
  1685. BOOL fTextChanged = FALSE;
  1686. REBARBANDINFO rbbi = {0};
  1687. RECT rc;
  1688. if (!prb || (!RB_ISVALIDINDEX(prb, uBand)) ||
  1689. !RBValidateBandInfo(&lprbbi, &rbbi))
  1690. return(FALSE);
  1691. prbb = RBGETBAND(prb, uBand);
  1692. if (lprbbi->fMask & RBBIM_TEXT)
  1693. {
  1694. if (!lprbbi->lpText || !prbb->lpText || lstrcmp(lprbbi->lpText, prbb->lpText))
  1695. {
  1696. if (lprbbi->lpText != prbb->lpText) {
  1697. Str_Set(&prbb->lpText, lprbbi->lpText);
  1698. fTextChanged = TRUE;
  1699. }
  1700. }
  1701. }
  1702. if (lprbbi->fMask & RBBIM_STYLE)
  1703. {
  1704. UINT fStylePrev = prbb->fStyle;
  1705. UINT fChanged = lprbbi->fStyle ^ fStylePrev;
  1706. prbb->fStyle = lprbbi->fStyle;
  1707. if (fChanged)
  1708. fRecalc = TRUE;
  1709. if ((prbb->fStyle & RBBS_FIXEDSIZE) && !(fStylePrev & RBBS_FIXEDSIZE))
  1710. prbb->cxMin = prbb->cx;
  1711. else if (fChanged & RBBS_FIXEDSIZE)
  1712. fRecalcMin = TRUE;
  1713. if (fChanged & RBBS_GRIPPERALWAYS)
  1714. fRecalcMin = TRUE;
  1715. if (fChanged & RBBS_HIDDEN)
  1716. RBShowBand(prb, uBand, !(prbb->fStyle & RBBS_HIDDEN));
  1717. if (fChanged & RBBS_HIDETITLE)
  1718. fTextChanged = TRUE;
  1719. // can't have both of these
  1720. if (prbb->fStyle & RBBS_FIXEDSIZE)
  1721. prbb->fStyle &= ~RBBS_BREAK;
  1722. }
  1723. // RBBIM_TEXT does calculations that want to take some RBBIM_STYLE bits
  1724. // into account, so delay those calculations until we grab the style bits.
  1725. //
  1726. if (fTextChanged && !(prbb->fStyle & RBBS_HIDDEN))
  1727. {
  1728. if (RBBCalcTextExtent(prb, prbb, NULL))
  1729. fRecalc = TRUE;
  1730. else
  1731. fRefresh = TRUE;
  1732. }
  1733. if (lprbbi->fMask & RBBIM_IDEALSIZE)
  1734. {
  1735. // HACKHACK: (tjgreen) Add an offset to the width the caller specifies.
  1736. // This offset gets clipped off in RBResizeChildren, so the child window is
  1737. // rendered with the width specified by caller, and we get a little space on
  1738. // the toolbar after the buttons. If caller specifies zero-width, though,
  1739. // we don't want this extra space, so don't add offset.
  1740. int cxIdeal = lprbbi->cxIdeal ? lprbbi->cxIdeal + CX_OFFSET : 0;
  1741. if (cxIdeal != prbb->cxIdeal) {
  1742. prbb->cxIdeal = cxIdeal;
  1743. fRecalcMin = TRUE;
  1744. fRecalc = TRUE;
  1745. }
  1746. }
  1747. if (lprbbi->fMask & RBBIM_SIZE)
  1748. {
  1749. if (prbb->cxRequest != (int) lprbbi->cx)
  1750. {
  1751. fRecalc = TRUE;
  1752. prbb->cxRequest = (int) lprbbi->cx;
  1753. }
  1754. if (prbb->fStyle & RBBS_FIXEDSIZE)
  1755. prbb->cxMin = prbb->cxRequest;
  1756. }
  1757. if (lprbbi->fMask & RBBIM_HEADERSIZE)
  1758. {
  1759. if ((lprbbi->cxHeader == -1) ||
  1760. !(prbb->fStyle & RBBS_FIXEDHEADERSIZE) ||
  1761. ((UINT)prbb->cxMin != lprbbi->cxHeader + prbb->cxMinChild)) {
  1762. if (lprbbi->cxHeader == -1) {
  1763. prbb->fStyle &= ~RBBS_FIXEDHEADERSIZE;
  1764. fRecalcMin = TRUE;
  1765. } else {
  1766. prbb->fStyle |= RBBS_FIXEDHEADERSIZE;
  1767. prbb->cxMin = lprbbi->cxHeader + prbb->cxMinChild;
  1768. }
  1769. fRecalc = TRUE;
  1770. fRefresh = TRUE;
  1771. }
  1772. }
  1773. if (lprbbi->fMask & RBBIM_COLORS)
  1774. {
  1775. prbb->clrFore = lprbbi->clrFore;
  1776. prbb->clrBack = lprbbi->clrBack;
  1777. fRefresh = TRUE;
  1778. }
  1779. if ((lprbbi->fMask & RBBIM_IMAGE) && (prbb->iImage != lprbbi->iImage))
  1780. {
  1781. BOOL fToggleBmp = ((prbb->iImage == -1) || (lprbbi->iImage == -1));
  1782. prbb->iImage = lprbbi->iImage;
  1783. if (fToggleBmp)
  1784. {
  1785. fRecalc = TRUE;
  1786. fRecalcMin = TRUE;
  1787. }
  1788. else
  1789. fRefresh = TRUE;
  1790. }
  1791. if (lprbbi->fMask & RBBIM_CHILD &&
  1792. lprbbi->hwndChild != prbb->hwndChild &&
  1793. (NULL == lprbbi->hwndChild ||
  1794. !IsChild(lprbbi->hwndChild, prb->ci.hwnd)))
  1795. {
  1796. if (IsWindow(prbb->hwndChild))
  1797. ShowWindow(prbb->hwndChild, SW_HIDE);
  1798. prbb->hwndChild = lprbbi->hwndChild;
  1799. if (prbb->hwndChild)
  1800. {
  1801. SetParent(prbb->hwndChild, prb->ci.hwnd);
  1802. ShowWindow(prbb->hwndChild, SW_SHOW);
  1803. }
  1804. fRecalc = TRUE;
  1805. }
  1806. if (lprbbi->fMask & RBBIM_CHILDSIZE)
  1807. {
  1808. UINT cyChildOld = prbb->cyChild;
  1809. if (lprbbi->cyMinChild != -1)
  1810. prbb->cyMinChild = lprbbi->cyMinChild;
  1811. if (prbb->fStyle & RBBS_VARIABLEHEIGHT) {
  1812. if (lprbbi->cyIntegral != -1)
  1813. prbb->cyIntegral = lprbbi->cyIntegral;
  1814. if (lprbbi->cyMaxChild != -1)
  1815. prbb->cyMaxChild = lprbbi->cyMaxChild;
  1816. if (lprbbi->cyChild != -1)
  1817. prbb->cyChild = lprbbi->cyChild;
  1818. if (prbb->cyChild < prbb->cyMinChild)
  1819. prbb->cyChild = prbb->cyMinChild;
  1820. if (prbb->cyChild > prbb->cyMaxChild)
  1821. prbb->cyChild = prbb->cyMaxChild;
  1822. // validate the child size. cyChild must be cyMinChild plux n*cyIntegral
  1823. if (prbb->cyIntegral) {
  1824. int iExtra;
  1825. iExtra = (prbb->cyChild - prbb->cyMinChild) % prbb->cyIntegral;
  1826. prbb->cyChild -= iExtra;
  1827. }
  1828. } else {
  1829. // if we're not in variable height mode, then
  1830. // the cyChild is the same as cyMinChild.
  1831. // this is a little peculiar, but done this way for backcompat.
  1832. // cyMinChild came before cyChild
  1833. prbb->cyChild = lprbbi->cyMinChild;
  1834. }
  1835. if (lprbbi->cxMinChild != (UINT)-1) {
  1836. // HACKHACK: (tjgreen) Add an offset to the width the caller specifies.
  1837. // This offset gets clipped off in RBResizeChildren, so the child window is
  1838. // rendered with the width specified by caller, and we get a little space on
  1839. // the toolbar after the buttons. However, if caller specifies zero-width or
  1840. // if the band is fixed size, we don't want this extra space, so don't add offset.
  1841. UINT cxMinChild = lprbbi->cxMinChild;
  1842. if ((lprbbi->cxMinChild != 0) && !(prbb->fStyle & RBBS_FIXEDSIZE))
  1843. cxMinChild += CX_OFFSET;
  1844. if (prbb->cxMinChild != cxMinChild) {
  1845. int cxOldHeaderMin = RBBHEADERWIDTH(prbb);
  1846. if (prbb->fStyle & RBBS_FIXEDSIZE)
  1847. fRecalc = TRUE;
  1848. prbb->cxMinChild = cxMinChild;
  1849. if (prbb->fStyle & RBBS_FIXEDHEADERSIZE)
  1850. prbb->cxMin = cxOldHeaderMin + prbb->cxMinChild;
  1851. fRecalcMin = TRUE;
  1852. }
  1853. if (cyChildOld != prbb->cyChild) {
  1854. // TODO: revisit optimization:
  1855. // if (RBBGetHeight(prb, prbb) != (UINT) prbb->cy)
  1856. fRecalc = TRUE;
  1857. }
  1858. }
  1859. }
  1860. if (lprbbi->fMask & RBBIM_BACKGROUND)
  1861. {
  1862. DIBSECTION dib;
  1863. if (lprbbi->hbmBack && !GetObject(lprbbi->hbmBack, sizeof(DIBSECTION), &dib))
  1864. return(FALSE);
  1865. prbb->hbmBack = lprbbi->hbmBack;
  1866. prbb->cxBmp = dib.dsBm.bmWidth;
  1867. prbb->cyBmp = dib.dsBm.bmHeight;
  1868. fRefresh = TRUE;
  1869. }
  1870. if (lprbbi->fMask & RBBIM_ID)
  1871. prbb->wID = lprbbi->wID;
  1872. if (lprbbi->fMask & RBBIM_LPARAM)
  1873. prbb->lParam = lprbbi->lParam;
  1874. if (fRecalcMin && !(prbb->fStyle & RBBS_HIDDEN))
  1875. RBBCalcMinWidth(prb, prbb);
  1876. if (fAllowRecalc) {
  1877. if (fRecalc)
  1878. RBResize(prb, FALSE);
  1879. if (fRefresh || fRecalc)
  1880. {
  1881. // '|| fRecalc' so we catch add/grow of text.
  1882. // testcase: remove title from band; add back; make sure the text
  1883. // shows up (used to just leave old band contents there)
  1884. SetRect(&rc, prbb->x, prbb->y, prbb->x + prbb->cx, prbb->y + prbb->cy);
  1885. RBInvalidateRect(prb, &rc);
  1886. }
  1887. }
  1888. return(TRUE);
  1889. }
  1890. // ----------------------------------------------------------------------------
  1891. //
  1892. // RBReallocBands
  1893. //
  1894. // reallocates the array of bands pointed to by prb->rbbList to the given
  1895. // number of bands
  1896. //
  1897. // ----------------------------------------------------------------------------
  1898. BOOL RBReallocBands(PRB prb, UINT cBands)
  1899. {
  1900. PRBB rbbList;
  1901. if (!(rbbList = (PRBB) CCLocalReAlloc(prb->rbbList, sizeof(RBB) * cBands)) && cBands)
  1902. return(FALSE);
  1903. prb->rbbList = rbbList;
  1904. return(TRUE);
  1905. }
  1906. //
  1907. // NOTES
  1908. // for now caller does this in two calls (query, set). eventually we
  1909. // should be able to have it do everything up front.
  1910. RBRecalcFirst(int nCmd, PRB prb, PRBB prbbDelHide)
  1911. {
  1912. switch (nCmd) {
  1913. case RBC_QUERY:
  1914. {
  1915. BOOL fRecalcFirst;
  1916. // if we're nuking the 1st visible guy,
  1917. // and there are visible guys after us,
  1918. // then we need to recompute stuff
  1919. //
  1920. // for a testcase, start w/:
  1921. // row1: 'standard buttons' + 'brand'
  1922. // row2: 'address' + 'links'
  1923. // now hide 'standard buttons', you should end up w/:
  1924. // row1: 'address' + 'links' + 'brand'
  1925. // if there's a bug, you'll end up w/ (since the break isn't recomputed):
  1926. // row1: 'brand'
  1927. // row2: 'address' + 'links'
  1928. // fRecalcFirst = (!uBand && prb->cBands);
  1929. // if brbbDelHide is the first non-hidden band, and there are other non-hidden bands after it, fRecalcFirst = TRUE;
  1930. fRecalcFirst = (RBEnumBand(prb, 0, RBBS_HIDDEN) == prbbDelHide) &&
  1931. (RBGetNextVisible(prb, prbbDelHide) <= RB_GETLASTBAND(prb));
  1932. return fRecalcFirst;
  1933. }
  1934. case RBC_SET: // set
  1935. {
  1936. PRBB prbb1, prbb2;
  1937. prbb1 = RBEnumBand(prb, 0, RBBS_HIDDEN);
  1938. if ((prbb1->fStyle & RBBS_FIXEDSIZE)
  1939. && (prbb2 = RBEnumBand(prb, 1, RBBS_HIDDEN)) <= RB_GETLASTBAND(prb)) {
  1940. // get rid of line break on NEW first item
  1941. prbb2->fStyle &= ~RBBS_BREAK;
  1942. }
  1943. if (prb->ci.style & RBS_FIXEDORDER) {
  1944. // BUGBUG not sure what this does...
  1945. // this is because the min width is now based on it's movability --
  1946. // and since we are deleting (or hiding) the first item,
  1947. // the new first item becomes immovable
  1948. RBBCalcMinWidth(prb, prbb1);
  1949. }
  1950. return TRUE;
  1951. }
  1952. default:
  1953. ASSERT(0);
  1954. }
  1955. return FALSE;
  1956. }
  1957. // ----------------------------------------------------------------------------
  1958. //
  1959. // RBShowBand
  1960. //
  1961. // updates show/hide state for the indicated band in the rebar's band array
  1962. // (rbbList).
  1963. //
  1964. // ----------------------------------------------------------------------------
  1965. BOOL RBShowBand(PRB prb, UINT uBand, BOOL fShow)
  1966. {
  1967. PRBB prbb;
  1968. BOOL fRecalcFirst;
  1969. if (!prb || (!RB_ISVALIDINDEX(prb, uBand)))
  1970. return(FALSE);
  1971. prbb = RBGETBAND(prb, uBand);
  1972. // if we're nuking the 1st visible guy,
  1973. // then we need to recompute stuff
  1974. fRecalcFirst = RBRecalcFirst(RBC_QUERY, prb, prbb);
  1975. if (fShow)
  1976. {
  1977. prbb->fStyle &= ~RBBS_HIDDEN;
  1978. if (!RBBCalcTextExtent(prb, prbb, NULL))
  1979. RBBCalcMinWidth(prb, prbb);
  1980. if (prbb->hwndChild)
  1981. ShowWindow(prbb->hwndChild, SW_SHOW);
  1982. }
  1983. else
  1984. {
  1985. prbb->fStyle |= RBBS_HIDDEN;
  1986. if (prbb->hwndChild)
  1987. ShowWindow(prbb->hwndChild, SW_HIDE);
  1988. }
  1989. if (fRecalcFirst)
  1990. RBRecalcFirst(RBC_SET, prb, NULL);
  1991. RBInvalidateRect(prb, NULL);
  1992. RBResize(prb, FALSE);
  1993. RBAutoSize(prb);
  1994. return(TRUE);
  1995. }
  1996. // ----------------------------------------------------------------------------
  1997. //
  1998. // RBDeleteBand
  1999. //
  2000. // deletes the indicated band from the rebar's band array (rbbList) and
  2001. // decrements the rebar's band count (cBands)
  2002. //
  2003. // ----------------------------------------------------------------------------
  2004. BOOL RBDeleteBand(PRB prb, UINT uBand)
  2005. {
  2006. PRBB prbb;
  2007. PRBB prbbStop;
  2008. BOOL fRecalcFirst;
  2009. NMREBAR nm = {0};
  2010. ASSERT(prb);
  2011. // we need to clean up
  2012. //
  2013. // a) captured band and
  2014. // b) hottracked band
  2015. //
  2016. // before we delete this band
  2017. if (prb->iCapture != -1) {
  2018. RBSendNotify(prb, prb->iCapture, RBN_ENDDRAG);
  2019. RBOnBeginDrag(prb, (UINT)-1);
  2020. }
  2021. if (!RB_ISVALIDINDEX(prb, uBand))
  2022. return FALSE;
  2023. prbb = RBGETBAND(prb, uBand);
  2024. // Notify the client of the delete
  2025. RBSendNotify(prb, uBand, RBN_DELETINGBAND);
  2026. nm.dwMask = RBNM_ID;
  2027. nm.wID = RBGETBAND(prb, uBand)->wID; // Save this
  2028. Str_Set(&prbb->lpText, NULL);
  2029. // don't destroy the hbmBack 'cause it's given to us by app
  2030. // if we're nuking the 1st visible guy,
  2031. // then we need to recompute stuff
  2032. // if this is the first visible guy and there are other visible bands after it, fRecalcFirst = TRUE
  2033. fRecalcFirst = RBRecalcFirst(RBC_QUERY, prb, prbb);
  2034. if (IsWindow(prbb->hwndChild))
  2035. ShowWindow(prbb->hwndChild, SW_HIDE);
  2036. // prbbStop gets the address of the last band
  2037. prbbStop = RB_GETLASTBAND(prb);
  2038. for ( ; prbb < prbbStop; prbb++)
  2039. *prbb = *(prbb + 1);
  2040. prb->cBands--;
  2041. if (prb->uResizeNext >= uBand && prb->uResizeNext > 0) {
  2042. // (defer RBBS_HIDDEN stuff to use of uResizeNext)
  2043. prb->uResizeNext--;
  2044. }
  2045. // Notify the client of the delete
  2046. CCSendNotify(&prb->ci, RBN_DELETEDBAND, &nm.hdr);
  2047. if (fRecalcFirst)
  2048. RBRecalcFirst(RBC_SET, prb, NULL);
  2049. RBReallocBands(prb, prb->cBands);
  2050. RBInvalidateRect(prb, NULL);
  2051. RBResize(prb, FALSE);
  2052. RBAutoSize(prb);
  2053. return(TRUE);
  2054. }
  2055. // ----------------------------------------------------------------------------
  2056. //
  2057. // RBInsertBand
  2058. //
  2059. // inserts a new band at the given position in the rebar's band array (rbbList),
  2060. // increments the rebar's band count (cBands), and sets the band's structure
  2061. // based on the given REBARBANDINFO structure.
  2062. //
  2063. // ----------------------------------------------------------------------------
  2064. BOOL RBInsertBand(PRB prb, UINT uBand, LPREBARBANDINFO lprbbi)
  2065. {
  2066. PRBB prbb;
  2067. REBARBANDINFO rbbi = {0};
  2068. if (!prb || !RBValidateBandInfo(&lprbbi, &rbbi))
  2069. return(FALSE);
  2070. if (uBand == -1)
  2071. uBand = prb->cBands;
  2072. else if (uBand > prb->cBands)
  2073. return(FALSE);
  2074. if (!RBReallocBands(prb, prb->cBands + 1))
  2075. return(FALSE);
  2076. ++prb->cBands;
  2077. MoveMemory(RBGETBAND(prb, uBand + 1), RBGETBAND(prb, uBand), (prb->cBands-1-uBand) * sizeof(prb->rbbList[0]));
  2078. prbb = RBGETBAND(prb, uBand);
  2079. // movememory does not zero init for us...
  2080. ZeroMemory(prbb, SIZEOF(RBB));
  2081. // Init text color
  2082. if (prb->clrText == CLR_NONE)
  2083. {
  2084. // Default to system text color
  2085. prbb->clrFore = CLR_DEFAULT;
  2086. }
  2087. else
  2088. {
  2089. // Default to rebar's custom text color
  2090. prbb->clrFore = CLR_NONE;
  2091. }
  2092. // Init background color
  2093. if (prb->clrBk == CLR_NONE)
  2094. {
  2095. // Default to system background color
  2096. prbb->clrBack = CLR_DEFAULT;
  2097. }
  2098. else
  2099. {
  2100. // Default to rebar's custom background color
  2101. prbb->clrBack = CLR_NONE;
  2102. }
  2103. prbb->iImage = -1;
  2104. prbb->cyMaxChild = MAXINT;
  2105. prbb->wChevState = DCHF_INACTIVE;
  2106. ASSERT(prbb->fStyle == 0);
  2107. ASSERT(prbb->lpText == NULL);
  2108. ASSERT(prbb->cxText == 0);
  2109. ASSERT(prbb->hwndChild == NULL);
  2110. ASSERT(prbb->cxMinChild == 0);
  2111. ASSERT(prbb->cyMinChild == 0);
  2112. ASSERT(prbb->hbmBack == 0);
  2113. ASSERT(prbb->x == 0);
  2114. ASSERT(prbb->y == 0);
  2115. ASSERT(prbb->cx == 0);
  2116. ASSERT(prbb->cy == 0);
  2117. if (!RBSetBandInfo(prb, uBand, lprbbi, FALSE))
  2118. {
  2119. RBDeleteBand(prb, uBand);
  2120. return(FALSE);
  2121. }
  2122. if (!(prbb->fStyle & RBBS_HIDDEN)) {
  2123. PRBB prbbFirst = RBEnumBand(prb, 0, RBBS_HIDDEN);
  2124. if (!prbb->cxMin)
  2125. RBBCalcMinWidth(prb, prbb);
  2126. if (prbbFirst != prbb) {
  2127. int cxMin = prbbFirst->cxMin;
  2128. RBBCalcMinWidth(prb, prbbFirst);
  2129. }
  2130. RBResize(prb, FALSE);
  2131. }
  2132. RBSizeBandToRowHeight(prb, uBand, (UINT)-1);
  2133. if (RBCountBands(prb, RBBS_HIDDEN) == 1) {
  2134. // typcially, when you insert a band, we put it in a row with another band.
  2135. // thus the total bounding rect doesn't change. however, on the addition of the first band,
  2136. // the bound rect does change, so we need to autosize as necessary.
  2137. RBAutoSize(prb);
  2138. }
  2139. return(TRUE);
  2140. }
  2141. #pragma code_seg(CODESEG_INIT)
  2142. LRESULT CALLBACK ReBarWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  2143. BOOL InitReBarClass(HINSTANCE hInstance)
  2144. {
  2145. WNDCLASS wc;
  2146. if (!GetClassInfo(hInstance, c_szReBarClass, &wc))
  2147. {
  2148. #ifndef WIN32
  2149. extern LRESULT CALLBACK _ReBarWndProc(HWND, UINT, WPARAM, LPARAM);
  2150. wc.lpfnWndProc = _ReBarWndProc;
  2151. #else
  2152. wc.lpfnWndProc = ReBarWndProc;
  2153. #endif
  2154. wc.lpszClassName= c_szReBarClass;
  2155. wc.style = CS_GLOBALCLASS | CS_DBLCLKS;
  2156. wc.cbClsExtra = 0;
  2157. wc.cbWndExtra = sizeof(PRB);
  2158. wc.hInstance = hInstance; // use DLL instance if in DLL
  2159. wc.hIcon = NULL;
  2160. wc.hCursor = NULL;
  2161. wc.hbrBackground= (HBRUSH)(COLOR_BTNFACE + 1);
  2162. wc.lpszMenuName = NULL;
  2163. if (!RegisterClass(&wc))
  2164. return(FALSE);
  2165. }
  2166. return(TRUE);
  2167. }
  2168. #pragma code_seg()
  2169. // get the first band in the same row as rbbRow
  2170. // n.b. we may return an RBBS_HIDDEN band!
  2171. PRBB RBGetFirstInRow(PRB prb, PRBB prbbRow)
  2172. {
  2173. // n.b. we don't pay attention to hidden here, that's up to caller.
  2174. // in fact we *can't*, since there might be no non-hidden guys left
  2175. // (e.g. when RBDestroy is deleting all the bands), in which case
  2176. // we'd loop forever.
  2177. while (prbbRow > RBGETBAND(prb, 0) && !RBISBANDSTARTOFROW(prbbRow)) {
  2178. RBCheckRangePtr(prb, prbbRow);
  2179. prbbRow--;
  2180. }
  2181. return prbbRow;
  2182. }
  2183. // get the last band in the same row as rbbRow.
  2184. // fStopAtFixed says whether to continue over fixed bands or
  2185. // stop at them
  2186. // n.b. we may return an RBBS_HIDDEN band!
  2187. PRBB RBGetLastInRow(PRB prb, PRBB prbbRow, BOOL fStopAtFixed)
  2188. {
  2189. do {
  2190. prbbRow++;
  2191. } while (prbbRow <= RB_GETLASTBAND(prb) && !RBISBANDSTARTOFROW(prbbRow) &&
  2192. (!fStopAtFixed || (prbbRow->fStyle & (RBBS_FIXEDSIZE|RBBS_HIDDEN)) == RBBS_FIXEDSIZE));
  2193. // loop steps to the start of the NEXT line
  2194. prbbRow--;
  2195. return prbbRow;
  2196. }
  2197. #ifdef DEBUG
  2198. BOOL RBCheckRangePtr(PRB prb, PRBB prbb)
  2199. {
  2200. if (prbb < RBGETBAND(prb, 0)) {
  2201. ASSERT(0);
  2202. return FALSE;
  2203. }
  2204. if (RB_GETLASTBAND(prb) + 1 < prbb) {
  2205. // +1 to allow for "p = first; p < last+1; p++" kinds of loops
  2206. ASSERT(0);
  2207. return FALSE;
  2208. }
  2209. return TRUE;
  2210. }
  2211. BOOL RBCheckRangeInd(PRB prb, INT_PTR i)
  2212. {
  2213. if (i < 0) {
  2214. ASSERT(0);
  2215. return FALSE;
  2216. }
  2217. if ((int) prb->cBands < i) {
  2218. // +1 to allow for "p = first; p < last+1; p++" kinds of loops
  2219. ASSERT(0);
  2220. return FALSE;
  2221. }
  2222. return TRUE;
  2223. }
  2224. #endif
  2225. //*** RBGetPrev, RBGetNext -- get prev (next) band, skipping guys
  2226. // of style uStyleSkip (e.g. RBBS_HIDDEN)
  2227. PRBB RBGetPrev(PRB prb, PRBB prbb, UINT uStyleSkip)
  2228. {
  2229. while (--prbb >= RBGETBAND(prb, 0)) {
  2230. if (prbb->fStyle & uStyleSkip)
  2231. continue;
  2232. break;
  2233. }
  2234. return prbb;
  2235. }
  2236. // when called with prbb=lastband, returns prbb++
  2237. // which is one past the end...
  2238. PRBB RBGetNext(PRB prb, PRBB prbb, UINT uStyleSkip)
  2239. {
  2240. while (++prbb <= RB_GETLASTBAND(prb)) {
  2241. if (prbb->fStyle & uStyleSkip)
  2242. continue;
  2243. break;
  2244. }
  2245. return prbb;
  2246. }
  2247. // this returns NULL when it hits the end
  2248. PRBB RBBNextVisible(PRB prb, PRBB prbb)
  2249. {
  2250. prbb = RBGetNextVisible(prb, prbb);
  2251. if (prbb > RB_GETLASTBAND(prb))
  2252. return NULL;
  2253. return prbb;
  2254. }
  2255. // this returns null when it hits the end
  2256. PRBB RBBPrevVisible(PRB prb, PRBB prbb)
  2257. {
  2258. prbb = RBGetPrevVisible(prb, prbb);
  2259. if (prbb < prb->rbbList)
  2260. return NULL;
  2261. return prbb;
  2262. }
  2263. //*** RBCountBands -- get count of bands, skipping guys
  2264. // of style uStyleSkip (e.g. RBBS_HIDDEN)
  2265. int RBCountBands(PRB prb, UINT uStyleSkip)
  2266. {
  2267. int i;
  2268. PRBB prbb;
  2269. if (prb->cBands == 0)
  2270. return 0;
  2271. i = 0;
  2272. for (prbb = RBGETBAND(prb, 0); prbb <= RB_GETLASTBAND(prb); prbb++) {
  2273. if (prbb->fStyle & uStyleSkip)
  2274. continue;
  2275. i++;
  2276. }
  2277. return i;
  2278. }
  2279. //*** RBEnumBand -- get Nth band, skipping guys
  2280. // of style uStyleSkip (e.g. RBBS_HIDDEN)
  2281. // 'skipping' means don't include in count
  2282. PRBB RBEnumBand(PRB prb, int i, UINT uStyleSkip)
  2283. {
  2284. PRBB prbb;
  2285. for (prbb = RBGETBAND(prb, 0); prbb <= RB_GETLASTBAND(prb); prbb++) {
  2286. if (prbb->fStyle & uStyleSkip)
  2287. continue;
  2288. if (i-- == 0)
  2289. break;
  2290. }
  2291. // if we found it, this is the band;
  2292. // if we ran out of bands, this is 1 past the end
  2293. return prbb;
  2294. }
  2295. // returns the minimum x position prbb can be
  2296. int RBMinX(PRB prb, PRBB prbb)
  2297. {
  2298. int xLimit = 0;
  2299. ASSERT(!(prbb->fStyle & RBBS_HIDDEN)); // o.w. might loop forever
  2300. while (!RBISBANDSTARTOFROW(prbb))
  2301. {
  2302. prbb--;
  2303. if (!(prbb->fStyle & RBBS_HIDDEN))
  2304. xLimit += _RBBandWidth(prb, prbb->cxMin);
  2305. }
  2306. return xLimit;
  2307. }
  2308. int RBMaxX(PRB prb, PRBB prbb)
  2309. {
  2310. PRBB prbbLast = prb->rbbList + prb->cBands;
  2311. int xLimit = 0;
  2312. PRBB prbbWalk;
  2313. for (prbbWalk = prbb; prbbWalk < prbbLast; prbbWalk++) {
  2314. if (prbbWalk->fStyle & RBBS_HIDDEN)
  2315. continue;
  2316. if (RBISBANDSTARTOFROW(prbbWalk))
  2317. break;
  2318. if (prbbWalk != prbb)
  2319. xLimit += _RBBandWidth(prb, prbbWalk->cxMin);
  2320. else
  2321. xLimit += prbbWalk->cxMin;
  2322. }
  2323. prbbWalk = RBGetPrevVisible(prb, prbbWalk); // prbbWalk--;
  2324. xLimit = prbbWalk->x + prbbWalk->cx - xLimit;
  2325. return xLimit;
  2326. }
  2327. PRBB RBGetPrevVisible(PRB prb, PRBB prbb)
  2328. {
  2329. return RBGetPrev(prb, prbb, RBBS_HIDDEN);
  2330. }
  2331. PRBB RBGetNextVisible(PRB prb, PRBB prbb)
  2332. {
  2333. return RBGetNext(prb, prbb, RBBS_HIDDEN);
  2334. }
  2335. BOOL RBMinimizeBand(PRB prb, UINT uBand, BOOL fAnim)
  2336. {
  2337. PRBB prbb;
  2338. if (!RB_ISVALIDINDEX(prb, uBand))
  2339. return FALSE;
  2340. prbb=RBGETBAND(prb,uBand);
  2341. if (prbb->fStyle & RBBS_FIXEDSIZE)
  2342. return FALSE;
  2343. ASSERT(!(prbb->fStyle & RBBS_HIDDEN));
  2344. if (RBISBANDSTARTOFROW(prbb)) {
  2345. // if it's the start of a row, the way to minimize it is to maximize the next guy
  2346. // if it's on the same row
  2347. prbb = RBGetNextVisible(prb, prbb);
  2348. if (prbb > RB_GETLASTBAND(prb) || RBISBANDSTARTOFROW(prbb))
  2349. return FALSE;
  2350. return RBMaximizeBand(prb, RBBANDTOINDEX(prb,prbb), FALSE, fAnim);
  2351. }
  2352. if (fAnim)
  2353. return RBSetBandPosAnim(prb, prbb, prbb->x + (prbb->cx - prbb->cxMin));
  2354. else
  2355. return RBSetBandPos(prb, prbb, prbb->x + (prbb->cx - prbb->cxMin));
  2356. }
  2357. // fIdeal - FALSE == full maximization...
  2358. // TRUE == go to cxIdeal
  2359. // fAnim - TRUE means we were called due to UI action (via RBToggleBand), so animate
  2360. BOOL RBMaximizeBand(PRB prb, UINT uBand, BOOL fIdeal, BOOL fAnim)
  2361. {
  2362. int x, dx;
  2363. BOOL fChanged = FALSE;
  2364. PRBB prbbMaximize;
  2365. if (!RB_ISVALIDINDEX(prb, uBand))
  2366. return FALSE;
  2367. prbbMaximize = RBGETBAND(prb,uBand);
  2368. if (prbbMaximize->fStyle & RBBS_FIXEDSIZE)
  2369. return FALSE;
  2370. dx = prbbMaximize->cxIdeal + RBBHEADERWIDTH(prbbMaximize) - prbbMaximize->cx;
  2371. if (fIdeal && dx > 0)
  2372. {
  2373. PRBB prbb;
  2374. // first move the next guy over if possible.
  2375. prbb = RBBNextVisible(prb, prbbMaximize);
  2376. if (prbb && (!RBISBANDSTARTOFROW(prbb)))
  2377. {
  2378. int dxRbb;
  2379. x = RBMaxX(prb, prbb);
  2380. // dxRbb is the maximum that prbb can move
  2381. dxRbb = x - prbb->x;
  2382. if (dxRbb > dx) {
  2383. // if that's more than enough space, then limit dx
  2384. dxRbb = dx;
  2385. }
  2386. x = prbb->x + dxRbb;
  2387. fChanged |= (fAnim)?RBSetBandPosAnim(prb, prbb, x):RBSetBandPos(prb,prbb,x);
  2388. dx -= dxRbb;
  2389. }
  2390. if (dx) {
  2391. int dxRbb;
  2392. // the one on the right didn't move enough.
  2393. // now move us back
  2394. x = RBMinX(prb, prbbMaximize);
  2395. dxRbb = prbbMaximize->x - x;
  2396. if (dxRbb > dx) {
  2397. x = prbbMaximize->x - dx;
  2398. }
  2399. fChanged |= (fAnim)?RBSetBandPosAnim(prb, prbbMaximize, x):RBSetBandPos(prb, prbbMaximize, x);
  2400. }
  2401. } else {
  2402. x = RBMinX(prb, prbbMaximize);
  2403. fChanged |= (fAnim)?RBSetBandPosAnim(prb, prbbMaximize, x):RBSetBandPos(prb, prbbMaximize, x);
  2404. prbbMaximize = RBBNextVisible(prb, prbbMaximize);
  2405. if (prbbMaximize && !RBISBANDSTARTOFROW(prbbMaximize)) {
  2406. x = RBMaxX(prb, prbbMaximize);
  2407. fChanged |= (fAnim)?RBSetBandPosAnim(prb, prbbMaximize, x):RBSetBandPos(prb, prbbMaximize, x);
  2408. }
  2409. }
  2410. return fChanged;
  2411. }
  2412. // ----------------------------------------------------------------------------
  2413. //
  2414. // RBToggleBand
  2415. //
  2416. // switches a band between it's maximized and minimized state, based on where
  2417. // the user clicked
  2418. //
  2419. // ----------------------------------------------------------------------------
  2420. void RBToggleBand(PRB prb, BOOL fAnim)
  2421. {
  2422. BOOL fDidSomething = FALSE;
  2423. // try to maximize this band. if failed (meaning already maximize)
  2424. // then minimize
  2425. if (CCSendNotify(&prb->ci, RBN_MINMAX, NULL))
  2426. return;
  2427. fDidSomething = RBMaximizeBand(prb, prb->iCapture, TRUE,fAnim);
  2428. if (!fDidSomething)
  2429. fDidSomething = RBMinimizeBand(prb, prb->iCapture,fAnim);
  2430. if (fDidSomething)
  2431. CCPlaySound(TEXT("ShowBand"));
  2432. }
  2433. // ----------------------------------------------------------------------------
  2434. //
  2435. // RBSetCursor
  2436. //
  2437. // sets the cursor to either the move cursor or the arrow cursor, depending
  2438. // on whether or not the cursor is on a band's caption
  2439. //
  2440. // ----------------------------------------------------------------------------
  2441. void RBSetCursor(PRB prb, int x, int y, BOOL fMouseDown)
  2442. {
  2443. int iBand;
  2444. RBHITTESTINFO rbht;
  2445. rbht.pt.x = x;
  2446. rbht.pt.y = y;
  2447. iBand = RBHitTest(prb, &rbht);
  2448. if (rbht.flags == RBHT_GRABBER)
  2449. {
  2450. if (fMouseDown)
  2451. SetCursor(LoadCursor(HINST_THISDLL, (prb->ci.style & CCS_VERT) ? MAKEINTRESOURCE(IDC_DIVOPENV) : MAKEINTRESOURCE(IDC_DIVOPEN) ));
  2452. else
  2453. SetCursor(LoadCursor(NULL, (prb->ci.style & CCS_VERT) ? IDC_SIZENS : IDC_SIZEWE));
  2454. return;
  2455. }
  2456. if ((fMouseDown) && ((rbht.flags == RBHT_GRABBER) || (rbht.flags == RBHT_CAPTION) && RBShouldDrawGripper(prb, RBGETBAND(prb, iBand))))
  2457. {
  2458. // No longer IE3 compatible, per RichSt
  2459. SetCursor(LoadCursor(NULL, IDC_SIZEALL));
  2460. return;
  2461. }
  2462. SetCursor(LoadCursor(NULL, IDC_ARROW));
  2463. }
  2464. // adjust's a band's (prbb) starting location to the given location
  2465. BOOL RBSetBandPos(PRB prb, PRBB prbb, int xLeft)
  2466. {
  2467. RECT rc;
  2468. PRBB prbbPrev;
  2469. int xRight;
  2470. BOOL fBandBorders = (prb->ci.style & RBS_BANDBORDERS);
  2471. BOOL fRight;
  2472. ASSERT(!(prbb->fStyle & RBBS_HIDDEN));
  2473. ASSERT((xLeft >= 0)); // We've got problems if someone is trying to set us negative
  2474. if (prbb->x == xLeft)
  2475. return(FALSE);
  2476. prbbPrev = RBGetPrevVisible(prb, prbb);
  2477. // band has moved within valid range -- adjust band sizes and redraw
  2478. // window
  2479. fRight = (prbb->x < xLeft);
  2480. SetRect(&rc, prbb->x, prbb->y, prbb->x + prbb->cxMin, prbb->y + prbb->cy);
  2481. xRight = prbb->x + prbb->cx;
  2482. prbb->x = xLeft;
  2483. prbb->cx = xRight - xLeft;
  2484. prbb->cxRequest = prbb->cx;
  2485. if (fRight)
  2486. {
  2487. //moving right
  2488. prbbPrev->cx = prbb->x - prbbPrev->x;
  2489. if (fBandBorders)
  2490. {
  2491. prbbPrev->cx -= g_cxEdge;
  2492. rc.left -= g_cxEdge;
  2493. }
  2494. prbbPrev->cxRequest = prbbPrev->cx;
  2495. //check for compacting of following bands
  2496. while (prbb->cx < prbb->cxMin)
  2497. {
  2498. prbb->cx = prbb->cxMin;
  2499. prbb->cxRequest = prbb->cx;
  2500. xLeft += RBBANDWIDTH(prb, prbb);
  2501. prbb = RBGetNextVisible(prb, prbb); // prbb++;
  2502. xRight = prbb->x + prbb->cx;
  2503. prbb->x = xLeft;
  2504. prbb->cx = xRight - xLeft;
  2505. prbb->cxRequest = prbb->cx;
  2506. }
  2507. rc.right = xLeft + prbb->cxMin;
  2508. }
  2509. else
  2510. {
  2511. //moving left
  2512. //check for compacting of preceding bands
  2513. CompactPrevious:
  2514. if (fBandBorders)
  2515. xLeft -= g_cxEdge;
  2516. prbbPrev->cx = xLeft - prbbPrev->x;
  2517. prbbPrev->cxRequest = prbbPrev->cx;
  2518. if (prbbPrev->cx < prbbPrev->cxMin)
  2519. {
  2520. prbbPrev->x = xLeft - prbbPrev->cxMin;
  2521. prbbPrev->cx = prbbPrev->cxMin;
  2522. prbbPrev->cxRequest = prbbPrev->cx;
  2523. xLeft = prbbPrev->x;
  2524. prbbPrev = RBGetPrevVisible(prb, prbbPrev); // prbbPrev--
  2525. goto CompactPrevious;
  2526. }
  2527. rc.left = xLeft;
  2528. }
  2529. if (fBandBorders)
  2530. rc.bottom += g_cyEdge / 2;
  2531. RBResizeChildren(prb);
  2532. if (RBInvalidateRect(prb, &rc))
  2533. UpdateWindow(prb->ci.hwnd);
  2534. return(TRUE);
  2535. }
  2536. BOOL RBSetBandPosAnim(PRB prb, PRBB prbb, int xLeft)
  2537. {
  2538. int ctr=0,dx, xCur = prbb->x;
  2539. DWORD dwStartTime;
  2540. if (xCur == xLeft)
  2541. return FALSE;
  2542. dwStartTime=GetTickCount();
  2543. dx = (xLeft - xCur)/RB_ANIMSTEPS;
  2544. if (dx != 0)
  2545. {
  2546. if (xCur < xLeft) {
  2547. // move right
  2548. for (; xCur < (xLeft-dx); ctr++,xCur += dx) {
  2549. RBSetBandPos(prb, prbb, xCur);
  2550. // If something caused us to take more than 10 times the time we
  2551. // should be, break out, and let the final RBSetBandPos finish
  2552. if (GetTickCount() > (dwStartTime + 10*RB_ANIMSTEPS*RB_ANIMSTEPTIME))
  2553. break;
  2554. Sleep(RB_ANIMSTEPTIME);
  2555. // Start slowing us down 80% of the way through
  2556. // Cut speed by 2/3 each time, but never move less than 4 pixels
  2557. if ((ctr >= 4*RB_ANIMSTEPS/5) && (dx >= 4))
  2558. dx = 2*dx/3;
  2559. }
  2560. }
  2561. else {
  2562. // move left
  2563. for (; xCur > (xLeft-dx); ctr++, xCur += dx) {
  2564. RBSetBandPos(prb, prbb, xCur);
  2565. if (GetTickCount() > (dwStartTime + 10*RB_ANIMSTEPS*RB_ANIMSTEPTIME))
  2566. break;
  2567. Sleep(RB_ANIMSTEPTIME);
  2568. if ((ctr >= 4*RB_ANIMSTEPS/5) && (dx <= -4))
  2569. dx = 2*dx/3;
  2570. }
  2571. }
  2572. }
  2573. RBSetBandPos(prb, prbb, xLeft);
  2574. return TRUE;
  2575. }
  2576. // ----------------------------------------------------------------------------
  2577. //
  2578. // RBDragSize
  2579. //
  2580. // adjust the captured band's starting location to the given location and
  2581. // redraw
  2582. //
  2583. // ----------------------------------------------------------------------------
  2584. BOOL RBDragSize(PRB prb, int xLeft)
  2585. {
  2586. return RBSetBandPos(prb, RBGETBAND(prb, prb->iCapture), xLeft);
  2587. }
  2588. void RBOnBeginDrag(PRB prb, UINT uBand)
  2589. {
  2590. prb->iCapture = (int)uBand;
  2591. prb->ptLastDragPos.x = -1;
  2592. prb->ptLastDragPos.y = -1;
  2593. if (prb->iCapture == -1) {
  2594. // aborting drag
  2595. prb->fParentDrag = FALSE;
  2596. prb->fFullOnDrag = FALSE;
  2597. // we could have unwrapped rows, in which case, we need to grow bands (but not wrap)
  2598. // to fill the empty space.
  2599. if (prb->ci.style & RBS_AUTOSIZE) {
  2600. RBSizeBandsToRect(prb, NULL);
  2601. RBSizeBandsToRowHeight(prb);
  2602. }
  2603. } else {
  2604. prb->fParentDrag = TRUE;
  2605. prb->fFullOnDrag = TRUE;
  2606. }
  2607. }
  2608. int minmax(int x, int min, int max)
  2609. {
  2610. x = max(x, min);
  2611. x = min(x, max);
  2612. return x;
  2613. }
  2614. // pass the break bit along
  2615. void RBPassBreak(PRB prb, PRBB prbbSrc, PRBB prbbDest)
  2616. {
  2617. if (prbbSrc->fStyle & RBBS_BREAK) {
  2618. prbbSrc->fStyle &= ~RBBS_BREAK;
  2619. if (prbbDest)
  2620. prbbDest->fStyle |= RBBS_BREAK;
  2621. }
  2622. }
  2623. void RBGetClientRect(PRB prb, LPRECT prc)
  2624. {
  2625. GetClientRect(prb->ci.hwnd, prc);
  2626. if (prb->ci.style & CCS_VERT)
  2627. FlipRect(prc);
  2628. }
  2629. //tells if prbb is the first band and the next band is fixed.
  2630. // if this is true then we need to do a recalc if we move prbb
  2631. BOOL RBRecalcIfMove(PRB prb, PRBB prbb)
  2632. {
  2633. if (RBEnumBand(prb, 0, RBBS_HIDDEN) == prbb) {
  2634. PRBB prbbNext = RBBNextVisible(prb, prbb);
  2635. if (prbbNext && prbbNext->fStyle & RBBS_FIXEDSIZE)
  2636. return TRUE;
  2637. }
  2638. return FALSE;
  2639. }
  2640. // find out if the prbb at it's min height could fit within the current window
  2641. // if all the others shrunk as much as they could
  2642. BOOL RBRoomForBandVert(PRB prb, PRBB prbbSkip)
  2643. {
  2644. int yExtra = 0;
  2645. int cBands = prb->cBands;
  2646. int iNewRowHeight = prbbSkip->cyMinChild;
  2647. PRBB prbb = RBGETBAND(prb, 0);
  2648. if (prb->ci.style & RBS_BANDBORDERS)
  2649. iNewRowHeight += g_cyEdge;
  2650. while (prbb) {
  2651. if (RBISBANDVISIBLE(prbb)) {
  2652. if (RBISBANDSTARTOFROW(prbb)) {
  2653. yExtra += RBGetRowHeightExtra(prb, &prbb, prbbSkip);
  2654. if (yExtra >= iNewRowHeight)
  2655. return TRUE;
  2656. continue;
  2657. }
  2658. }
  2659. prbb = RBBNextVisible(prb, prbb);
  2660. }
  2661. return FALSE;
  2662. }
  2663. // we should make a new row if prbb isn't the start of the row already
  2664. // and we're off the end of the control
  2665. //
  2666. // poweruser hack of holding the control down will make a new row if you hit the border between lines
  2667. BOOL RBMakeNewRow(PRB prb, PRBB prbb, int y)
  2668. {
  2669. BOOL fRet = FALSE;
  2670. RECT rc;
  2671. // if we're off the top of the control, move this band to the end (or beginning)
  2672. RBGetClientRect(prb, &rc);
  2673. InflateRect(&rc, 0, -g_cyEdge);
  2674. if (!(prb->ci.style & RBS_FIXEDORDER)) {
  2675. int iOutsideLimit = g_cyEdge * 4; // how far do you have to move outside the bounds of the window to force a new row
  2676. if (RBRoomForBandVert(prb, prbb)) {
  2677. iOutsideLimit = -g_cyEdge;
  2678. }
  2679. if (y < rc.top - iOutsideLimit) { // top of control
  2680. PRBB prbbNext = RBEnumBand(prb, 0, RBBS_HIDDEN);
  2681. if (prbbNext == prbb)
  2682. prbbNext = RBBNextVisible(prb, prbb);
  2683. fRet |= RBMoveBand(prb, RBBANDTOINDEX(prb, prbb), 0);
  2684. ASSERT(prbbNext <= RB_GETLASTBAND(prb));
  2685. if (prbbNext && !(prbbNext->fStyle & RBBS_BREAK)) {
  2686. prbbNext->fStyle |= RBBS_BREAK;
  2687. fRet = TRUE;
  2688. }
  2689. } else if (y >= rc.bottom + iOutsideLimit) { // move to the end
  2690. if (!(prbb->fStyle & RBBS_BREAK)) {
  2691. prbb->fStyle |= RBBS_BREAK;
  2692. fRet = TRUE;
  2693. }
  2694. fRet |= RBMoveBand(prb, RBBANDTOINDEX(prb, prbb), prb->cBands-1);
  2695. } else {
  2696. // create a new row in the middle
  2697. if (!RBISBANDSTARTOFROW(prbb) && GetAsyncKeyState(VK_CONTROL) < 0) {
  2698. // make sure they're on different rows and on the border
  2699. if (y > prbb->y + prbb->cy && (y < prbb->y + prbb->cy + g_cyEdge)) {
  2700. PRBB prbbLast = RBGetLastInRow(prb, prbb, FALSE); // move it right before the first in this row
  2701. prbb->fStyle |= RBBS_BREAK;
  2702. RBMoveBand(prb, RBBANDTOINDEX(prb, prbb), RBBANDTOINDEX(prb, prbbLast));
  2703. fRet = TRUE;
  2704. }
  2705. }
  2706. }
  2707. } else {
  2708. // fixed guys can't move, they can only make a new row
  2709. if (!RBISBANDSTARTOFROW(prbb)) {
  2710. if (y > prbb->y + prbb->cy) {
  2711. prbb->fStyle |= RBBS_BREAK;
  2712. fRet = TRUE;
  2713. }
  2714. }
  2715. }
  2716. if (fRet)
  2717. RBResize(prb, FALSE);
  2718. return fRet;
  2719. }
  2720. // ----------------------------------------------------------------------------
  2721. //
  2722. // RBDragBand
  2723. //
  2724. // resizes the currently tracked band based on the user's mouse movement as
  2725. // indicated in the given point (x, y)
  2726. //
  2727. // ----------------------------------------------------------------------------
  2728. void RBDragBand(PRB prb, int x, int y)
  2729. {
  2730. PRBB prbb = RBGETBAND(prb, prb->iCapture);
  2731. int iHit;
  2732. // Do nothing if the mouse didn't actually move
  2733. // otherwise, multiple WM_MOUSEMOVE messages will be generated by resizing windows
  2734. if (x==prb->ptLastDragPos.x && y==prb->ptLastDragPos.y)
  2735. return;
  2736. else
  2737. {
  2738. prb->ptLastDragPos.x = x;
  2739. prb->ptLastDragPos.y = y;
  2740. }
  2741. if (prb->ci.style & CCS_VERT)
  2742. SWAP(x,y, int);
  2743. if (!prb->fFullOnDrag)
  2744. {
  2745. // don't begin dragging until mouse is moved outside of an edge-thick
  2746. // tolerance border
  2747. if ((y < (prb->ptCapture.y - g_cyEdge)) || (y > (prb->ptCapture.y + g_cyEdge)) ||
  2748. (x < (prb->ptCapture.x - g_cxEdge)) || (x > (prb->ptCapture.x + g_cxEdge))) {
  2749. // did parent abort?
  2750. if (RBSendNotify(prb, prb->iCapture, RBN_BEGINDRAG))
  2751. return;
  2752. if (!RB_ISVALIDBAND(prb, prbb)) {
  2753. // somebody responded to RBN_BEGINDRAG by nuking bands; bail
  2754. return;
  2755. }
  2756. prb->fFullOnDrag = TRUE;
  2757. } else
  2758. return;
  2759. }
  2760. // bail for right now on fRecalcIfMoved (ie3 did the same thing). nice feature for later
  2761. if (!RBCanBandMove(prb, prbb))
  2762. return;
  2763. /* what type of drag operation depends on what we drag hit on.
  2764. if we hit on the band before us, or ourself
  2765. and it's the same row
  2766. and we're not the first band of the row
  2767. then we just to a size move
  2768. otherwise if we hit on a band then we do a move
  2769. if we hit outside of any band, we grow to meet the cursor
  2770. in all of the above, a band that's hit must be NOT fixed and not hidden
  2771. */
  2772. iHit = _RBHitTest(prb, NULL, x, y);
  2773. if (iHit != -1) {
  2774. BOOL fResize = FALSE;
  2775. PRBB prbbPrev = RBBPrevVisible(prb, prbb);
  2776. PRBB prbbHit = RBGETBAND(prb, iHit);
  2777. prbbHit = RBGetPrev(prb, ++prbbHit, RBBS_FIXEDSIZE); // skip over fixed guys
  2778. ASSERT(prbbHit >= prb->rbbList);
  2779. // this should never happen.
  2780. if (prbbHit < prb->rbbList)
  2781. return;
  2782. iHit = RBBANDTOINDEX(prb, prbbHit);
  2783. // if we're on the same row ... and it's us or the previous one
  2784. if (prbbHit->y == prbb->y && (prbbHit == prbb || prbbHit == prbbPrev)) {
  2785. if (x < RB_GRABWIDTH && !(prb->ci.style & RBS_FIXEDORDER)) {
  2786. // special case dragging to the far left. there's no other way to move to first in row
  2787. RBPassBreak(prb, prbbHit, prbb);
  2788. if (RBMoveBand(prb, prb->iCapture, iHit))
  2789. fResize = TRUE;
  2790. } else if (!RBISBANDSTARTOFROW(prbb)) {
  2791. // and we're not the first band of the row
  2792. // then just size it
  2793. int xLeft = prb->xStart + (x - prb->ptCapture.x);
  2794. xLeft = minmax(xLeft, RBMinX(prb, prbb), RBMaxX(prb, prbb));
  2795. RBDragSize(prb, xLeft);
  2796. }
  2797. } else if (RBMakeNewRow(prb, prbb, y)) {
  2798. } else { // otherwise do a move if we're not in a fixed order
  2799. if (!(prb->ci.style & RBS_FIXEDORDER)) {
  2800. if (iHit < RBBANDTOINDEX(prb, prbb))
  2801. iHit++; // +1 because if you hit a band, you're moving to the right of him
  2802. // if one with a break is moving, the next one inherits the break
  2803. RBPassBreak(prb, prbb, RBBNextVisible(prb, prbb));
  2804. RBMoveBand(prb, prb->iCapture, iHit);
  2805. } else {
  2806. if (iHit < RBBANDTOINDEX(prb, prbb))
  2807. RBPassBreak(prb, prbb, RBBNextVisible(prb, prbb));
  2808. }
  2809. fResize = TRUE;
  2810. }
  2811. if (fResize)
  2812. RBResize(prb, FALSE);
  2813. } else
  2814. RBMakeNewRow(prb, prbb, y);
  2815. }
  2816. HPALETTE RBSetPalette(PRB prb, HPALETTE hpal)
  2817. {
  2818. HPALETTE hpalOld = prb->hpal;
  2819. if (hpal != hpalOld) {
  2820. if (!prb->fUserPalette) {
  2821. if (prb->hpal) {
  2822. DeleteObject(prb->hpal);
  2823. prb->hpal = NULL;
  2824. }
  2825. }
  2826. if (hpal) {
  2827. prb->fUserPalette = TRUE;
  2828. prb->hpal = hpal;
  2829. }
  2830. RBInvalidateRect(prb, NULL);
  2831. }
  2832. return hpalOld;
  2833. }
  2834. // ----------------------------------------------------------------------------
  2835. //
  2836. // RBDestroy
  2837. //
  2838. // frees all memory allocated by rebar, including rebar structure
  2839. //
  2840. // ----------------------------------------------------------------------------
  2841. BOOL RBDestroy(PRB prb)
  2842. {
  2843. UINT c = prb->cBands;
  2844. RBSetRedraw(prb, FALSE);
  2845. RBSetRecalc(prb, FALSE);
  2846. while (c--)
  2847. RBDeleteBand(prb, c);
  2848. // so that we don't keep trying to autosize
  2849. prb->ci.style &= ~RBS_AUTOSIZE;
  2850. ASSERT(!prb->rbbList);
  2851. RBSetPalette(prb, NULL);
  2852. if (prb->hFont && prb->fFontCreated) {
  2853. DeleteObject(prb->hFont);
  2854. }
  2855. if ((prb->ci.style & RBS_TOOLTIPS) && IsWindow(prb->hwndToolTips))
  2856. {
  2857. DestroyWindow (prb->hwndToolTips);
  2858. prb->hwndToolTips = NULL;
  2859. }
  2860. // don't destroy the himl 'cause it's given to us by app
  2861. SetWindowPtr(prb->ci.hwnd, 0, 0);
  2862. if (prb->hDragProxy)
  2863. DestroyDragProxy(prb->hDragProxy);
  2864. LocalFree((HLOCAL) prb);
  2865. return(TRUE);
  2866. }
  2867. // ----------------------------------------------------------------------------
  2868. //
  2869. // RBInitPaletteHack
  2870. //
  2871. // this is a hack to use the halftone palette until we have a way of asking
  2872. // the client what palette they are using
  2873. //
  2874. // ----------------------------------------------------------------------------
  2875. void RBInitPaletteHack(PRB prb)
  2876. {
  2877. if (!prb->fUserPalette) {
  2878. HDC hdc = CreateCompatibleDC(NULL);
  2879. if (hdc) {
  2880. if (GetDeviceCaps(hdc, BITSPIXEL) <= 8) {
  2881. if (prb->hpal)
  2882. DeleteObject(prb->hpal);
  2883. prb->hpal = CreateHalftonePalette(hdc); // this is a hack
  2884. }
  2885. DeleteDC(hdc);
  2886. }
  2887. }
  2888. }
  2889. LRESULT RBIDToIndex(PRB prb, UINT id)
  2890. {
  2891. UINT i;
  2892. REBARBANDINFO rbbi;
  2893. rbbi.cbSize = sizeof(REBARBANDINFO);
  2894. rbbi.fMask = RBBIM_ID;
  2895. for (i = 0; i < prb->cBands; i++) {
  2896. if (RBGetBandInfo(prb, i, &rbbi)) {
  2897. if (rbbi.wID == (WORD)id)
  2898. return i;
  2899. }
  2900. }
  2901. return -1;
  2902. }
  2903. LRESULT RBGetRowHeight(PRB prb, UINT uRow)
  2904. {
  2905. if (uRow < prb->cBands)
  2906. {
  2907. // move back to start of line
  2908. PRBB prbbFirst = RBGetFirstInRow(prb, RBGETBAND(prb, uRow));
  2909. PRBB prbbLast = RBGetLastInRow(prb, RBGETBAND(prb, uRow), FALSE);
  2910. return RBGetLineHeight(prb, RBBANDTOINDEX(prb, prbbFirst), RBBANDTOINDEX(prb, prbbLast));
  2911. }
  2912. return (LRESULT)-1;
  2913. }
  2914. // fOneStep == whether to allow only one cyIntegral or as many as will fit to
  2915. // fill dy
  2916. int RBGrowBand(PRB prb, PRBB prbb, int dy, BOOL fOneStep)
  2917. {
  2918. int iDirection = dy / ABS(dy);
  2919. int dyBand = 0; // how much the band changes
  2920. int cyNewHeight;
  2921. if (prbb->cyIntegral &&
  2922. prbb->cyIntegral <= (UINT)ABS(dy)) {
  2923. // get the proposed new size
  2924. if (fOneStep)
  2925. dyBand = (prbb->cyIntegral * iDirection);
  2926. else {
  2927. int iNumOfIntegrals;
  2928. // don't let it grow more than the max allowed
  2929. if (dy >= 0) {
  2930. if ((int)(prbb->cyMaxChild - prbb->cyChild) < dy) {
  2931. dy = (int)(prbb->cyMaxChild - prbb->cyChild);
  2932. }
  2933. } else {
  2934. if ((int)(prbb->cyMinChild - prbb->cyChild) > dy) {
  2935. dy = (int)(prbb->cyMinChild - prbb->cyChild);
  2936. }
  2937. }
  2938. iNumOfIntegrals = (dy / (int) prbb->cyIntegral);
  2939. dyBand = (prbb->cyIntegral * iNumOfIntegrals);
  2940. }
  2941. cyNewHeight = ((int)prbb->cyChild) + dyBand;
  2942. // make sure the new size is legal
  2943. if ((int)prbb->cyMinChild <= cyNewHeight && ((UINT)cyNewHeight) <= prbb->cyMaxChild) {
  2944. prbb->cyChild = cyNewHeight;
  2945. RBResize(prb, TRUE);
  2946. } else
  2947. dyBand = 0;
  2948. }
  2949. return dyBand;
  2950. }
  2951. // returns the delta in size that the rebar is from prc.
  2952. // taking into account vertical mode
  2953. int RBSizeDifference(PRB prb, LPRECT prc)
  2954. {
  2955. int d;
  2956. d = (RB_ISVERT(prb) ? RECTWIDTH(*prc) : RECTHEIGHT(*prc))
  2957. - prb->cy;
  2958. return d;
  2959. }
  2960. // returns how much this row could shrink
  2961. int RBGetRowHeightExtra(PRB prb, PRBB *pprbb, PRBB prbbSkip)
  2962. {
  2963. // this is the largest minimum child size for the row.
  2964. // even if something is not at it's min size, if it's smaller than this
  2965. // then it doesn't matter because someone else on that row can't be sized
  2966. int yLimit = 0;
  2967. int yExtra = 0;
  2968. PRBB prbb = *pprbb;
  2969. while (prbb) {
  2970. if (prbb != prbbSkip) {
  2971. int yMin;
  2972. int yExtraBand = 0;
  2973. // the min height is the cyChild if it's not variable height
  2974. yMin = prbb->cyChild;
  2975. if (prbb->fStyle & RBBS_VARIABLEHEIGHT)
  2976. {
  2977. // if it is variable height, and there's still room to shrink, then cyMinChild is
  2978. // the minimum.
  2979. if (prbb->cyChild > prbb->cyMinChild + prbb->cyIntegral) {
  2980. yMin = prbb->cyMinChild;
  2981. yExtraBand = prbb->cyChild - prbb->cyMinChild;
  2982. }
  2983. }
  2984. if (yMin == yLimit) {
  2985. if (yExtraBand > yExtra)
  2986. yExtra = yExtraBand;
  2987. } else if (yMin > yLimit) {
  2988. yExtra = yExtraBand;
  2989. }
  2990. }
  2991. prbb = RBBNextVisible(prb, prbb);
  2992. }
  2993. *pprbb = prbb;
  2994. return yExtra;
  2995. }
  2996. // are allt he bands at the minimum size?
  2997. BOOL RBBandsAtMinHeight(PRB prb)
  2998. {
  2999. BOOL fRet = TRUE;
  3000. int cBands = prb->cBands;
  3001. PRBB prbb = RBGETBAND(prb, 0);
  3002. while (prbb) {
  3003. if (RBISBANDVISIBLE(prbb)) {
  3004. if (RBISBANDSTARTOFROW(prbb)) {
  3005. fRet = RBROWATMINHEIGHT(prb, &prbb);
  3006. if (!fRet)
  3007. break;
  3008. continue;
  3009. }
  3010. }
  3011. prbb = RBBNextVisible(prb, prbb);
  3012. }
  3013. return fRet;
  3014. }
  3015. // this is like RBSizeBarToRect except that it resizes theactual bands if they
  3016. // are VARIABLEHEIGHT
  3017. BOOL RBSizeBandsToRect(PRB prb, LPRECT prc)
  3018. {
  3019. int dy;
  3020. int iDirection = 0;
  3021. BOOL fChanged = FALSE;
  3022. BOOL fChangedThisLoop;
  3023. UINT cBands;
  3024. RECT rc;
  3025. BOOL fRedrawOld;
  3026. if (prc)
  3027. rc = *prc;
  3028. else {
  3029. GetClientRect(prb->ci.hwnd, &rc);
  3030. }
  3031. fRedrawOld = RBSetRedraw(prb, FALSE);
  3032. // this is the amount we need to grow by
  3033. do {
  3034. BOOL fOneStep = TRUE;
  3035. cBands = prb->cBands;
  3036. fChangedThisLoop = FALSE;
  3037. // if there's only one row, we don't need to iterate through all the rows slowly
  3038. if (RBGetRowCount(prb) == 1)
  3039. fOneStep = FALSE;
  3040. dy = RBSizeDifference(prb, &rc);
  3041. // ensure that we alway size in the same direction.
  3042. // it's possible to get on the border and flip flop in an infinite
  3043. // loop. this happens when we size both horizontally and vertically down
  3044. // beyond the minimum.
  3045. if (iDirection == 0)
  3046. iDirection = dy;
  3047. else if (dy * iDirection < 0)
  3048. break;
  3049. while (cBands-- && dy) {
  3050. // when we're resizing the entire rebar, we want to divvy up
  3051. // the growth among all the bands (rather than give it all to
  3052. // a single guy). uResizeNext goes round-robin thru the bands.
  3053. PRBB prbb = RBGETBAND(prb, prb->uResizeNext);
  3054. if (prb->uResizeNext == 0)
  3055. prb->uResizeNext = prb->cBands -1;
  3056. else
  3057. prb->uResizeNext--;
  3058. if (prbb->fStyle & RBBS_HIDDEN)
  3059. continue;
  3060. if (prbb->fStyle & RBBS_VARIABLEHEIGHT) {
  3061. int d;
  3062. // if it's a variable height kind of guy, grow/shrink it
  3063. d = RBGrowBand(prb, prbb, dy, fOneStep);
  3064. dy -= d;
  3065. if (d) {
  3066. fChanged = TRUE;
  3067. fChangedThisLoop = TRUE;
  3068. break;
  3069. }
  3070. }
  3071. }
  3072. // if we're shrinking
  3073. // and we didn't get completely satisfied. we need to overshoot
  3074. // so that no bands hang off the end and get cut off
  3075. if (dy < 0 && !fChangedThisLoop && !RBBandsAtMinHeight(prb)) {
  3076. if (rc.bottom > rc.top) {
  3077. rc.bottom -= 1;
  3078. fChangedThisLoop = TRUE;
  3079. }
  3080. }
  3081. } while (fChangedThisLoop);
  3082. RBSetRedraw(prb, fRedrawOld);
  3083. return fChanged;
  3084. }
  3085. void RBSizeBandToRowHeight(PRB prb, int i, UINT uRowHeight)
  3086. {
  3087. PRBB prbb = RBGETBAND(prb, i);
  3088. if (prbb && prbb->fStyle & RBBS_VARIABLEHEIGHT) {
  3089. if (uRowHeight == (UINT)-1)
  3090. uRowHeight = (UINT) RBGetRowHeight(prb, i);
  3091. if (uRowHeight > prbb->cyChild) {
  3092. RBGrowBand(prb, prbb, (uRowHeight - prbb->cyChild),
  3093. FALSE);
  3094. }
  3095. }
  3096. }
  3097. // in the process of sizing, one band in a row of several bands might have
  3098. // grow pretty large. we need to let the other bands have a chance to fill
  3099. // the extra space as well
  3100. void RBSizeBandsToRowHeight(PRB prb)
  3101. {
  3102. UINT i;
  3103. UINT iRowHeight = (UINT)-1;
  3104. for (i = 0; i < prb->cBands; i++) {
  3105. PRBB prbb = RBGETBAND(prb, i);
  3106. if (prbb->fStyle & RBBS_HIDDEN)
  3107. continue;
  3108. if (RBISBANDSTARTOFROW(prbb))
  3109. iRowHeight = (UINT) RBGetRowHeight(prb, i);
  3110. RBSizeBandToRowHeight(prb, i, iRowHeight);
  3111. }
  3112. }
  3113. // this will add/remove rebar band breaks to get to the requested size.
  3114. // it returns TRUE/FALSE whether something was done or not.
  3115. LRESULT RBSizeBarToRect(PRB prb, LPRECT prc)
  3116. {
  3117. BOOL fChanged = FALSE;
  3118. RECT rc;
  3119. BOOL fRedrawOld = RBSetRedraw(prb, FALSE);
  3120. if (!prc) {
  3121. GetClientRect(prb->ci.hwnd, &rc);
  3122. prc = &rc;
  3123. }
  3124. if (prb->cBands) {
  3125. int c;
  3126. UINT cBands = prb->cBands;
  3127. BOOL fChangedThisLoop = TRUE;
  3128. BOOL fGrowing = TRUE;
  3129. // if we're shrinking the rebar, we first want to shrink the bands before we start
  3130. // removing breaks
  3131. c = RBSizeDifference(prb, prc);
  3132. if (c < 0)
  3133. fGrowing = FALSE;
  3134. if (!fGrowing) {
  3135. fChanged = RBSizeBandsToRect(prb, prc);
  3136. if (!RBBandsAtMinHeight(prb)) {
  3137. // if we're shrinking and all the bands are not down to
  3138. // the minimum height, don't try doing any of the breaking stuff
  3139. goto Bail;
  3140. }
  3141. } else if (RB_ISVERT(prb)) {
  3142. // if we're in vertical mode, give preference to
  3143. // sizing bands before breaking
  3144. fChanged = RBSizeBandsToRect(prb, prc);
  3145. }
  3146. while (fChangedThisLoop && prb->cBands) {
  3147. int cyRowHalf = (int) RBGetRowHeight(prb, prb->cBands-1) / 2 ;
  3148. REBARBANDINFO rbbi;
  3149. PRBB prbb;
  3150. fChangedThisLoop = FALSE;
  3151. rbbi.cbSize = sizeof(REBARBANDINFO);
  3152. rbbi.fMask = RBBIM_STYLE;
  3153. c = RBSizeDifference(prb, prc);
  3154. if (c < -cyRowHalf) {
  3155. // we've shrunk the rebar, try to remove breaks
  3156. while (--cBands)
  3157. {
  3158. prbb = RBGETBAND(prb, cBands);
  3159. if (prbb->fStyle & RBBS_HIDDEN)
  3160. continue;
  3161. if (prbb->fStyle & RBBS_BREAK)
  3162. {
  3163. fChanged = TRUE;
  3164. fChangedThisLoop = TRUE;
  3165. rbbi.fStyle = prbb->fStyle & ~RBBS_BREAK;
  3166. RBSetBandInfo(prb, cBands, &rbbi, TRUE);
  3167. break;
  3168. }
  3169. }
  3170. } else if (c > cyRowHalf) {
  3171. // we're enlarging the rebar
  3172. while (--cBands)
  3173. {
  3174. prbb = RBGETBAND(prb, cBands);
  3175. if (prbb->fStyle & RBBS_HIDDEN)
  3176. continue;
  3177. if (!(prbb->fStyle & (RBBS_BREAK | RBBS_FIXEDSIZE)))
  3178. {
  3179. // no break here, add it
  3180. fChanged = TRUE;
  3181. fChangedThisLoop = TRUE;
  3182. rbbi.fStyle = (prbb->fStyle | RBBS_BREAK);
  3183. RBSetBandInfo(prb, cBands, &rbbi, TRUE);
  3184. break;
  3185. }
  3186. }
  3187. }
  3188. };
  3189. // if we did as much breaking as we could
  3190. // and we walked all the way down to the 0th band (we start at the Nth band)
  3191. // then we try to grow the bands that are VARIABLEHEIGHT
  3192. // for fGrowing, see comment at top of function
  3193. //
  3194. // wedo the % because cBands == prb->cBands if we didn't go through
  3195. // any of the breaking loops at all
  3196. if (!(cBands % prb->cBands) && fGrowing)
  3197. fChanged |= RBSizeBandsToRect(prb, prc);
  3198. }
  3199. Bail:
  3200. RBSizeBandsToRowHeight(prb);
  3201. RBSetRedraw(prb, fRedrawOld);
  3202. return (LRESULT)fChanged;
  3203. }
  3204. void RBAutoSize(PRB prb)
  3205. {
  3206. NMRBAUTOSIZE nm;
  3207. // if this is an internal autosize call, but we're not in autosize mode
  3208. // do nothing
  3209. if (!(prb->ci.style & RBS_AUTOSIZE))
  3210. return;
  3211. GetClientRect(prb->ci.hwnd, &nm.rcTarget);
  3212. nm.fChanged = (BOOL) RBSizeBarToRect(prb, &nm.rcTarget);
  3213. GetClientRect(prb->ci.hwnd, &nm.rcActual);
  3214. CCSendNotify(&prb->ci, RBN_AUTOSIZE, &nm.hdr);
  3215. }
  3216. LRESULT RBGetBandBorders(PRB prb, int wParam, LPRECT prc)
  3217. {
  3218. BOOL fBandBorders = (prb->ci.style & RBS_BANDBORDERS);
  3219. PRBB prbb = &prb->rbbList[wParam];
  3220. prc->left = RBBHEADERWIDTH(prbb);
  3221. if (fBandBorders) {
  3222. prc->left += 2*g_cxEdge;
  3223. prc->right = 0;
  3224. prc->top = g_cyEdge/2;
  3225. prc->bottom = g_cyEdge /2;
  3226. }
  3227. if (prb->ci.style & CCS_VERT)
  3228. FlipRect(prc);
  3229. return 0;
  3230. }
  3231. void RBOnStyleChanged(PRB prb, WPARAM wParam, LPSTYLESTRUCT lpss)
  3232. {
  3233. if (wParam == GWL_STYLE)
  3234. {
  3235. DWORD dwChanged;
  3236. prb->ci.style = lpss->styleNew;
  3237. dwChanged = (lpss->styleOld ^ lpss->styleNew);
  3238. // update to reflect style change
  3239. #ifndef WINNT
  3240. TraceMsg(TF_REBAR, "rebar window style changed %x", prb->ci.style);
  3241. #endif
  3242. if (dwChanged & CCS_VERT)
  3243. {
  3244. UINT i;
  3245. for (i = 0; i < prb->cBands; i++) {
  3246. if (RBGETBAND(prb, i)->fStyle & RBBS_HIDDEN)
  3247. continue;
  3248. RBBCalcMinWidth(prb, RBGETBAND(prb, i));
  3249. }
  3250. RBResize(prb, TRUE);
  3251. RBInvalidateRect(prb, NULL);
  3252. }
  3253. if (dwChanged & RBS_REGISTERDROP) {
  3254. if (prb->ci.style & RBS_REGISTERDROP) {
  3255. ASSERT(!prb->hDragProxy);
  3256. prb->hDragProxy = CreateDragProxy(prb->ci.hwnd, RebarDragCallback, TRUE);
  3257. } else {
  3258. ASSERT(prb->hDragProxy);
  3259. DestroyDragProxy(prb->hDragProxy);
  3260. }
  3261. }
  3262. } else if (wParam == GWL_EXSTYLE) {
  3263. //
  3264. // If the RTL_MIRROR extended style bit had changed, let's
  3265. // repaint the control window
  3266. //
  3267. if ((prb->ci.dwExStyle&RTL_MIRRORED_WINDOW) != (lpss->styleNew&RTL_MIRRORED_WINDOW)) {
  3268. RBInvalidateRect(prb, NULL);
  3269. }
  3270. //
  3271. // Save the new ex-style bits
  3272. //
  3273. prb->ci.dwExStyle = lpss->styleNew;
  3274. }
  3275. }
  3276. void RBOnMouseMove(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, PRB prb)
  3277. {
  3278. RelayToToolTips(prb->hwndToolTips, hwnd, uMsg, wParam, lParam);
  3279. if (prb->iCapture != -1)
  3280. {
  3281. // captured band -- mouse is down
  3282. if (hwnd != GetCapture() && !prb->fParentDrag)
  3283. {
  3284. RBSendNotify(prb, prb->iCapture, RBN_ENDDRAG);
  3285. RBOnBeginDrag(prb, (UINT)-1);
  3286. }
  3287. else
  3288. RBDragBand(prb, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  3289. }
  3290. else
  3291. {
  3292. // hottracking
  3293. int iBand;
  3294. PRBB prbb = NULL;
  3295. PRBB prbbHotOld = prb->prbbHot;
  3296. RBHITTESTINFO rbht;
  3297. rbht.pt.x = GET_X_LPARAM(lParam);
  3298. rbht.pt.y = GET_Y_LPARAM(lParam);
  3299. iBand = RBHitTest(prb, &rbht);
  3300. if (iBand != -1)
  3301. prbb = RBGETBAND(prb, iBand);
  3302. if (prbbHotOld && (prbbHotOld->wChevState & DCHF_PUSHED))
  3303. return;
  3304. if (prbb && (rbht.flags & RBHT_CHEVRON))
  3305. {
  3306. SetCapture(hwnd);
  3307. RBUpdateChevronState(prb, prbb, DCHF_HOT);
  3308. if (prbb == prbbHotOld)
  3309. prbbHotOld = NULL;
  3310. }
  3311. if (prbbHotOld)
  3312. {
  3313. CCReleaseCapture(&prb->ci);
  3314. RBUpdateChevronState(prb, prbbHotOld, DCHF_INACTIVE);
  3315. }
  3316. }
  3317. }
  3318. void RBOnPushChevron(HWND hwnd, PRB prb, PRBB prbb, LPARAM lParamNM)
  3319. {
  3320. NMREBARCHEVRON nm;
  3321. nm.uBand = RBBANDTOINDEX(prb, prbb);
  3322. nm.wID = prbb->wID;
  3323. nm.lParam = prbb->lParam;
  3324. nm.lParamNM = lParamNM;
  3325. CopyRect(&nm.rc, &prbb->rcChevron);
  3326. if (RB_ISVERT(prb))
  3327. FlipRect(&nm.rc);
  3328. RBUpdateChevronState(prb, prbb, DCHF_PUSHED);
  3329. CCReleaseCapture(&prb->ci);
  3330. CCSendNotify(&prb->ci, RBN_CHEVRONPUSHED, &nm.hdr);
  3331. RBUpdateChevronState(prb, prb->prbbHot, DCHF_INACTIVE);
  3332. }
  3333. LRESULT CALLBACK ReBarWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  3334. {
  3335. PRB prb = (PRB) GetWindowPtr(hwnd, 0);
  3336. int iBand;
  3337. // bail if no prb unless at creation time
  3338. if (!prb && !(uMsg == WM_NCCREATE))
  3339. goto CallDWP;
  3340. switch (uMsg)
  3341. {
  3342. case WM_SETREDRAW:
  3343. if (prb->ci.iVersion >= 5)
  3344. RBSetRecalc(prb, BOOLFROMPTR(wParam));
  3345. return RBSetRedraw(prb, BOOLFROMPTR(wParam));
  3346. case WM_NCCREATE:
  3347. #define lpcs ((LPCREATESTRUCT) lParam)
  3348. CCCreateWindow();
  3349. InitGlobalColors();
  3350. if (!(prb = (PRB) LocalAlloc(LPTR, sizeof(RB))))
  3351. return(0L);
  3352. SetWindowPtr(hwnd, 0, prb);
  3353. prb->iCapture = -1;
  3354. prb->clrBk = CLR_NONE;
  3355. prb->clrText = CLR_NONE;
  3356. // Init the dwSize because we block-copy it back to the app
  3357. prb->clrsc.dwSize = sizeof(COLORSCHEME);
  3358. prb->clrsc.clrBtnHighlight = prb->clrsc.clrBtnShadow = CLR_DEFAULT;
  3359. prb->fRedraw = TRUE;
  3360. prb->fRecalc = TRUE;
  3361. // note, zero init memory from above
  3362. CIInitialize(&prb->ci, hwnd, lpcs);
  3363. if (!(prb->ci.style & (CCS_TOP | CCS_NOMOVEY | CCS_BOTTOM)))
  3364. {
  3365. prb->ci.style |= CCS_TOP;
  3366. SetWindowLong(hwnd, GWL_STYLE, prb->ci.style);
  3367. }
  3368. RBSetFont(prb, 0);
  3369. if (lpcs->lpCreateParams)
  3370. RBSetBarInfo(prb, (LPREBARINFO) (lpcs->lpCreateParams));
  3371. #undef lpcs
  3372. return TRUE;
  3373. case WM_DESTROY:
  3374. CCDestroyWindow();
  3375. RBDestroy(prb);
  3376. SetWindowPtr(hwnd, 0, 0);
  3377. break;
  3378. case WM_CREATE:
  3379. // Do delayed stuff for speed.
  3380. PostMessage(hwnd, RB_PRIV_DODELAYEDSTUFF, 0, 0);
  3381. goto CallDWP;
  3382. case RB_PRIV_DODELAYEDSTUFF:
  3383. // Delay done stuff for speed:
  3384. if (prb->ci.style & RBS_REGISTERDROP)
  3385. prb->hDragProxy = CreateDragProxy(prb->ci.hwnd, RebarDragCallback, TRUE);
  3386. if (prb->ci.style & RBS_TOOLTIPS)
  3387. {
  3388. TOOLINFO ti;
  3389. // don't bother setting the rect because we'll do it below
  3390. // in FlushToolTipsMgr;
  3391. ti.cbSize = sizeof(ti);
  3392. ti.uFlags = TTF_IDISHWND;
  3393. ti.hwnd = hwnd;
  3394. ti.uId = (UINT_PTR)hwnd;
  3395. ti.lpszText = 0;
  3396. prb->hwndToolTips = CreateWindow(c_szSToolTipsClass, NULL,
  3397. WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  3398. hwnd, NULL, (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), NULL);
  3399. SendMessage(prb->hwndToolTips, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO) &ti);
  3400. }
  3401. RBInitPaletteHack(prb);
  3402. break;
  3403. case WM_NCHITTEST:
  3404. {
  3405. RBHITTESTINFO rbht;
  3406. int iBand;
  3407. rbht.pt.x = GET_X_LPARAM(lParam);
  3408. rbht.pt.y = GET_Y_LPARAM(lParam);
  3409. ScreenToClient(prb->ci.hwnd, &rbht.pt);
  3410. iBand = RBHitTest(prb, &rbht);
  3411. {
  3412. NMMOUSE nm;
  3413. LRESULT lres;
  3414. nm.dwItemSpec = iBand;
  3415. nm.pt = rbht.pt;
  3416. nm.dwHitInfo = rbht.flags;
  3417. // send to the parent to give them a chance to override
  3418. lres = CCSendNotify(&prb->ci, NM_NCHITTEST, &nm.hdr);
  3419. if (lres)
  3420. return lres;
  3421. }
  3422. }
  3423. return HTCLIENT;
  3424. case WM_NCCALCSIZE:
  3425. if (prb->ci.style & WS_BORDER)
  3426. {
  3427. InflateRect((LPRECT) lParam, -g_cxEdge, -g_cyEdge);
  3428. break;
  3429. }
  3430. goto CallDWP;
  3431. case WM_NCPAINT:
  3432. if (prb->ci.style & WS_BORDER)
  3433. {
  3434. RECT rc;
  3435. HDC hdc;
  3436. GetWindowRect(hwnd, &rc);
  3437. OffsetRect(&rc, -rc.left, -rc.top);
  3438. hdc = GetWindowDC(hwnd);
  3439. CCDrawEdge(hdc, &rc, EDGE_ETCHED, BF_RECT, &(prb->clrsc));
  3440. ReleaseDC(hwnd, hdc);
  3441. break;
  3442. }
  3443. goto CallDWP;
  3444. case WM_PALETTECHANGED:
  3445. if ((HWND)wParam == hwnd)
  3446. break;
  3447. case WM_QUERYNEWPALETTE:
  3448. // Want to pass FALSE if WM_QUERYNEWPALETTE...
  3449. RBRealize(prb, NULL, uMsg == WM_PALETTECHANGED, uMsg == WM_PALETTECHANGED);
  3450. return TRUE;
  3451. case WM_PAINT:
  3452. case WM_PRINTCLIENT:
  3453. RBPaint(prb, (HDC)wParam);
  3454. break;
  3455. case WM_ERASEBKGND:
  3456. if (RBEraseBkgnd(prb, (HDC) wParam, -1))
  3457. return(TRUE);
  3458. goto CallDWP;
  3459. case WM_SYSCOLORCHANGE:
  3460. RBInitPaletteHack(prb);
  3461. if (prb->hwndToolTips)
  3462. SendMessage(prb->hwndToolTips, uMsg, wParam, lParam);
  3463. InitGlobalColors();
  3464. InvalidateRect(prb->ci.hwnd, NULL, TRUE);
  3465. break;
  3466. case RB_SETPALETTE:
  3467. return (LRESULT)RBSetPalette(prb, (HPALETTE)lParam);
  3468. case RB_GETPALETTE:
  3469. return (LRESULT)prb->hpal;
  3470. case WM_SIZE:
  3471. RBAutoSize(prb);
  3472. RBResize(prb, FALSE);
  3473. break;
  3474. case WM_GETFONT:
  3475. return((LRESULT) (prb ? prb->hFont : NULL));
  3476. case WM_COMMAND:
  3477. case WM_DRAWITEM:
  3478. case WM_MEASUREITEM:
  3479. case WM_VKEYTOITEM:
  3480. case WM_CHARTOITEM:
  3481. SendMessage(prb->ci.hwndParent, uMsg, wParam, lParam);
  3482. break;
  3483. case WM_LBUTTONDBLCLK: // DBLCLK sent in place of LBUTTONDOWN
  3484. case WM_RBUTTONDOWN: // right button drags too
  3485. case WM_LBUTTONDOWN:
  3486. {
  3487. RBHITTESTINFO rbht;
  3488. PRBB prbb = NULL;
  3489. rbht.pt.x = GET_X_LPARAM(lParam);
  3490. rbht.pt.y = GET_Y_LPARAM(lParam);
  3491. RelayToToolTips(prb->hwndToolTips, hwnd, uMsg, wParam, lParam);
  3492. iBand = RBHitTest(prb, &rbht);
  3493. if (iBand != -1)
  3494. prbb = RBGETBAND(prb, iBand);
  3495. if (!prbb)
  3496. /* nothing */ ;
  3497. else if (rbht.flags & RBHT_CHEVRON)
  3498. {
  3499. RBOnPushChevron(hwnd, prb, prbb, 0);
  3500. }
  3501. else if (rbht.flags != RBHT_CLIENT && RBShouldDrawGripper(prb, prbb))
  3502. {
  3503. prb->iCapture = iBand;
  3504. prb->ptCapture = rbht.pt;
  3505. if (prb->ci.style & CCS_VERT)
  3506. SWAP(prb->ptCapture.x, prb->ptCapture.y, int);
  3507. prb->xStart = prbb->x;
  3508. SetCapture(hwnd);
  3509. prb->fFullOnDrag = FALSE;
  3510. if (uMsg == WM_LBUTTONDBLCLK && (prb->ci.style & RBS_DBLCLKTOGGLE))
  3511. RBToggleBand(prb,TRUE);
  3512. }
  3513. }
  3514. break;
  3515. case WM_SETCURSOR:
  3516. // Give the parent first crack, if it sets the cursor then
  3517. // leave it at that. Otherwise if the cursor is over our
  3518. // window then set it to what we want it to be.
  3519. if (!DefWindowProc(hwnd, uMsg, wParam, lParam) && (hwnd == (HWND)wParam))
  3520. {
  3521. POINT pt;
  3522. GetMessagePosClient(prb->ci.hwnd, &pt);
  3523. RBSetCursor(prb, pt.x, pt.y, (HIWORD(lParam) == WM_LBUTTONDOWN || HIWORD(lParam) == WM_RBUTTONDOWN));
  3524. }
  3525. return TRUE;
  3526. case WM_MOUSEMOVE:
  3527. RBOnMouseMove(hwnd, uMsg, wParam, lParam, prb);
  3528. break;
  3529. case WM_RBUTTONUP:
  3530. if (!prb->fFullOnDrag && !prb->fParentDrag) {
  3531. CCReleaseCapture(&prb->ci);
  3532. // if we're not doing drag drop, go to def window proc so that
  3533. // wm_contextmenu gets propagated
  3534. RBOnBeginDrag(prb, (UINT)-1);
  3535. goto CallDWP;
  3536. }
  3537. // fall through
  3538. case WM_LBUTTONUP:
  3539. RelayToToolTips(prb->hwndToolTips, hwnd, uMsg, wParam, lParam);
  3540. if (prb->iCapture != -1)
  3541. {
  3542. UINT uiIndex;
  3543. if (!prb->fParentDrag)
  3544. CCReleaseCapture(&prb->ci);
  3545. // if there was no significant mouse motion, treat as a click
  3546. if (!(prb->ci.style & RBS_DBLCLKTOGGLE) && !prb->fFullOnDrag)
  3547. RBToggleBand(prb,TRUE);
  3548. RBGETBAND(prb, prb->iCapture)->fStyle &= ~RBBS_DRAGBREAK;
  3549. CCSendNotify(&prb->ci, RBN_LAYOUTCHANGED, NULL);
  3550. RBSendNotify(prb, prb->iCapture, RBN_ENDDRAG);
  3551. RBOnBeginDrag(prb, (UINT)-1);
  3552. for (uiIndex = 0; uiIndex < prb->cBands; uiIndex++) {
  3553. if (RBGETBAND(prb, uiIndex)->fStyle & RBBS_HIDDEN)
  3554. continue;
  3555. RBBCalcMinWidth(prb, RBGETBAND(prb, uiIndex));
  3556. }
  3557. RBSizeBandsToRect(prb, NULL);
  3558. RBInvalidateRect(prb, NULL);
  3559. }
  3560. break;
  3561. case WM_WININICHANGE:
  3562. InitGlobalMetrics(wParam);
  3563. if (prb->fFontCreated)
  3564. RBSetFont(prb, wParam);
  3565. if (prb->hwndToolTips)
  3566. SendMessage(prb->hwndToolTips, uMsg, wParam, lParam);
  3567. break;
  3568. case WM_SETFONT:
  3569. RBOnSetFont(prb, (HFONT)wParam);
  3570. break;
  3571. case WM_NOTIFYFORMAT:
  3572. return(CIHandleNotifyFormat(&prb->ci, lParam));
  3573. case WM_NOTIFY:
  3574. // We are just going to pass this on to the real parent
  3575. // Note that -1 is used as the hwndFrom. This prevents SendNotifyEx
  3576. // from updating the NMHDR structure.
  3577. return(SendNotifyEx(prb->ci.hwndParent, (HWND) -1,
  3578. ((LPNMHDR) lParam)->code, (LPNMHDR) lParam, prb->ci.bUnicode));
  3579. case WM_STYLECHANGED:
  3580. RBOnStyleChanged(prb, wParam, (LPSTYLESTRUCT)lParam);
  3581. break;
  3582. #ifdef KEYBOARDCUES
  3583. case WM_UPDATEUISTATE:
  3584. if (CCOnUIState(&(prb->ci), WM_UPDATEUISTATE, wParam, lParam))
  3585. {
  3586. InvalidateRect(hwnd, NULL, TRUE);
  3587. }
  3588. goto CallDWP;
  3589. #endif
  3590. #ifdef UNICODE
  3591. case RB_SETBANDINFOA:
  3592. case RB_INSERTBANDA:
  3593. if (EVAL(lParam))
  3594. {
  3595. LPWSTR lpStrings = NULL;
  3596. LPSTR lpAnsiString;
  3597. int iResult;
  3598. // lParam starts out pointing to a REBARBANDINFOA, and
  3599. // we secretly change it into a REBARBANDINFOW, and then
  3600. // change it back.
  3601. LPREBARBANDINFOW prbiW = (LPREBARBANDINFOW)lParam;
  3602. LPREBARBANDINFOA prbiA = (LPREBARBANDINFOA)lParam;
  3603. COMPILETIME_ASSERT(sizeof(REBARBANDINFOW) == sizeof(REBARBANDINFOA));
  3604. // BUGBUG - raymondc - Is it safe to modify the incoming
  3605. // REBARBANDINFOA structure?
  3606. lpAnsiString = prbiA->lpText;
  3607. if ((prbiA->fMask & RBBIM_TEXT) && prbiA->lpText) {
  3608. lpStrings = ProduceWFromA(prb->ci.uiCodePage, lpAnsiString);
  3609. if (!lpStrings)
  3610. return -1;
  3611. // Presto! Now it's a REBARBANDINFOW!
  3612. prbiW->lpText = lpStrings;
  3613. }
  3614. if (uMsg == RB_INSERTBANDA)
  3615. iResult = RBInsertBand(prb, (UINT) wParam, prbiW);
  3616. else
  3617. iResult = RBSetBandInfo(prb, (UINT) wParam, prbiW, TRUE);
  3618. // Change-o! Now it's a REBARBANDINFOA!
  3619. prbiA->lpText = lpAnsiString;
  3620. if (lpStrings)
  3621. FreeProducedString(lpStrings);
  3622. return iResult;
  3623. }
  3624. #endif
  3625. case RB_INSERTBAND:
  3626. return(RBInsertBand(prb, (UINT) wParam, (LPREBARBANDINFO) lParam));
  3627. case RB_DELETEBAND:
  3628. return(RBDeleteBand(prb, (UINT) wParam));
  3629. case RB_SHOWBAND:
  3630. return(RBShowBand(prb, (UINT) wParam, BOOLFROMPTR(lParam)));
  3631. #ifdef UNICODE
  3632. case RB_GETBANDINFOA:
  3633. {
  3634. LPREBARBANDINFOA prbbi = (LPREBARBANDINFOA)lParam;
  3635. LPWSTR pszW = NULL;
  3636. LPSTR lpAnsiString = prbbi->lpText;
  3637. int iResult;
  3638. if (prbbi->fMask & RBBIM_TEXT) {
  3639. pszW = LocalAlloc(LPTR, prbbi->cch * sizeof(WCHAR));
  3640. if (!pszW)
  3641. return 0;
  3642. prbbi->lpText = (LPSTR)pszW;
  3643. }
  3644. iResult = RBGetBandInfo(prb, (UINT)wParam, (LPREBARBANDINFO)lParam);
  3645. if (pszW) {
  3646. ConvertWToAN(prb->ci.uiCodePage, lpAnsiString, prbbi->cch, (LPWSTR)prbbi->lpText, -1);
  3647. prbbi->lpText = lpAnsiString;
  3648. LocalFree(pszW);
  3649. }
  3650. return iResult;
  3651. }
  3652. #endif
  3653. // we have getbandinfoold because in ie3, we did not thunk
  3654. // and getbandinfo always return OS native string (dumb)
  3655. case RB_GETBANDINFOOLD:
  3656. case RB_GETBANDINFO:
  3657. return(RBGetBandInfo(prb, (UINT) wParam, (LPREBARBANDINFO) lParam));
  3658. case RB_GETTOOLTIPS:
  3659. return (LPARAM)prb->hwndToolTips;
  3660. case RB_SETTOOLTIPS:
  3661. prb->hwndToolTips = (HWND)wParam;
  3662. break;
  3663. case RB_SETBKCOLOR:
  3664. {
  3665. COLORREF clr = prb->clrBk;
  3666. prb->clrBk = (COLORREF)lParam;
  3667. if (clr != prb->clrBk)
  3668. InvalidateRect(prb->ci.hwnd, NULL, TRUE);
  3669. return clr;
  3670. }
  3671. case RB_GETBKCOLOR:
  3672. return prb->clrBk;
  3673. case RB_SETTEXTCOLOR:
  3674. {
  3675. COLORREF clr = prb->clrText;
  3676. prb->clrText = (COLORREF)lParam;
  3677. return clr;
  3678. }
  3679. case RB_GETTEXTCOLOR:
  3680. return prb->clrText;
  3681. case RB_IDTOINDEX:
  3682. return RBIDToIndex(prb, (UINT) wParam);
  3683. case RB_GETROWCOUNT:
  3684. return(RBGetRowCount(prb));
  3685. case RB_GETROWHEIGHT:
  3686. return RBGetRowHeight(prb, (UINT)wParam);
  3687. case RB_GETBANDBORDERS:
  3688. return RBGetBandBorders(prb, (UINT)wParam, (LPRECT)lParam);
  3689. case RB_GETBANDCOUNT:
  3690. return(prb->cBands);
  3691. case RB_SETBANDINFO:
  3692. return(RBSetBandInfo(prb, (UINT) wParam, (LPREBARBANDINFO) lParam, TRUE));
  3693. case RB_GETBARINFO:
  3694. return(RBGetBarInfo(prb, (LPREBARINFO) lParam));
  3695. case RB_SETBARINFO:
  3696. return(RBSetBarInfo(prb, (LPREBARINFO) lParam));
  3697. case RB_SETPARENT:
  3698. {
  3699. HWND hwndOld = prb->ci.hwndParent;
  3700. prb->ci.hwndParent = (HWND) wParam;
  3701. return (LRESULT)hwndOld;
  3702. }
  3703. break;
  3704. case RB_GETRECT:
  3705. if (RB_ISVALIDINDEX(prb, wParam))
  3706. {
  3707. PRBB prbb = RBGETBAND(prb, (int) wParam);
  3708. LPRECT lprc = (LPRECT) lParam;
  3709. lprc->left = prbb->x;
  3710. lprc->top = prbb->y;
  3711. lprc->right = prbb->x + prbb->cx;
  3712. lprc->bottom = prbb->y + prbb->cy;
  3713. return(TRUE);
  3714. }
  3715. break;
  3716. case RB_HITTEST:
  3717. return(RBHitTest(prb, (LPRBHITTESTINFO) lParam));
  3718. case RB_SIZETORECT:
  3719. return RBSizeBarToRect(prb, (LPRECT)lParam);
  3720. case RB_BEGINDRAG:
  3721. if (RB_ISVALIDINDEX(prb, wParam)) {
  3722. // -1 means do it yourself.
  3723. // -2 means use what you had saved before
  3724. if (lParam != (LPARAM)-2) {
  3725. if (lParam == (LPARAM)-1) {
  3726. GetMessagePosClient(prb->ci.hwnd, &prb->ptCapture);
  3727. } else {
  3728. prb->ptCapture.x = GET_X_LPARAM(lParam);
  3729. prb->ptCapture.y = GET_Y_LPARAM(lParam);
  3730. }
  3731. if (prb->ci.style & CCS_VERT)
  3732. SWAP(prb->ptCapture.x, prb->ptCapture.y, int);
  3733. }
  3734. prb->xStart = RBGETBAND(prb, (UINT)wParam)->x;
  3735. RBOnBeginDrag(prb, (UINT)wParam);
  3736. }
  3737. break;
  3738. case RB_GETBARHEIGHT:
  3739. return RBGETBARHEIGHT(prb);
  3740. case RB_ENDDRAG:
  3741. RBOnBeginDrag(prb, (UINT)-1);
  3742. break;
  3743. case RB_DRAGMOVE:
  3744. if (prb->iCapture != -1) {
  3745. if (lParam == (LPARAM)-1) {
  3746. lParam = GetMessagePosClient(prb->ci.hwnd, NULL);
  3747. }
  3748. RBDragBand(prb, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  3749. }
  3750. break;
  3751. case RB_MINIMIZEBAND:
  3752. RBMinimizeBand(prb, (UINT) wParam,FALSE);
  3753. break;
  3754. case RB_MAXIMIZEBAND:
  3755. RBMaximizeBand(prb, (UINT)wParam, BOOLFROMPTR(lParam),FALSE);
  3756. break;
  3757. case RB_MOVEBAND:
  3758. if (!RB_ISVALIDINDEX(prb,wParam) || !RB_ISVALIDINDEX(prb,lParam))
  3759. break;
  3760. return RBMoveBand(prb, (UINT) wParam, (UINT) lParam);
  3761. case RB_GETDROPTARGET:
  3762. if (!prb->hDragProxy)
  3763. prb->hDragProxy = CreateDragProxy(prb->ci.hwnd, RebarDragCallback, FALSE);
  3764. GetDragProxyTarget(prb->hDragProxy, (IDropTarget**)lParam);
  3765. break;
  3766. case RB_GETCOLORSCHEME:
  3767. {
  3768. LPCOLORSCHEME lpclrsc = (LPCOLORSCHEME) lParam;
  3769. if (lpclrsc) {
  3770. if (lpclrsc->dwSize == sizeof(COLORSCHEME))
  3771. *lpclrsc = prb->clrsc;
  3772. }
  3773. return (LRESULT) lpclrsc;
  3774. }
  3775. case RB_SETCOLORSCHEME:
  3776. if (lParam) {
  3777. if (((LPCOLORSCHEME) lParam)->dwSize == sizeof(COLORSCHEME)) {
  3778. prb->clrsc.clrBtnHighlight = ((LPCOLORSCHEME) lParam)->clrBtnHighlight;
  3779. prb->clrsc.clrBtnShadow = ((LPCOLORSCHEME) lParam)->clrBtnShadow;
  3780. InvalidateRect(hwnd, NULL, FALSE);
  3781. if (prb->ci.style & WS_BORDER)
  3782. CCInvalidateFrame(hwnd);
  3783. }
  3784. }
  3785. break;
  3786. case RB_PUSHCHEVRON:
  3787. if (RB_ISVALIDINDEX(prb, wParam)) {
  3788. PRBB prbb = RBGETBAND(prb, wParam);
  3789. RBOnPushChevron(hwnd, prb, prbb, lParam);
  3790. }
  3791. break;
  3792. default:
  3793. {
  3794. LRESULT lres;
  3795. if (CCWndProc(&prb->ci, uMsg, wParam, lParam, &lres))
  3796. return lres;
  3797. }
  3798. CallDWP:
  3799. return(DefWindowProc(hwnd, uMsg, wParam, lParam));
  3800. }
  3801. return(0L);
  3802. }