rebar.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 134k
Category:

Windows Kernel

Development Platform:

Visual C++

  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.     
  176.     return MAKELONG(dx, dy);
  177. }
  178. ///
  179. //
  180. // Map a rect to parent should be based on the visual right edge
  181. // for calculating the client coordinates for a RTL mirrored windows.
  182. // This routine should only be used when calculating client
  183. // coordinates in a RTL mirrored window. [samera]
  184. //
  185. BOOL MapRectInRTLMirroredWindow( LPRECT lprc, HWND hwnd)
  186. {
  187.     int iWidth  = lprc->right - lprc->left;
  188.     int iHeight = lprc->bottom- lprc->top;
  189.     RECT rc={0,0,0,0};
  190.     if (hwnd) {
  191.         GetClientRect(hwnd, &rc);
  192.         MapWindowPoints(hwnd, NULL, (LPPOINT)&rc.left, 2);
  193.     }
  194.     lprc->left = rc.right - lprc->right;
  195.     lprc->top  = lprc->top-rc.top;
  196.     lprc->bottom = lprc->top + iHeight;
  197.     lprc->right  = lprc->left + iWidth;
  198.     return TRUE;
  199. }
  200. int _RBBandWidth(PRB prb, int x)
  201. {
  202.     if (prb->ci.style & RBS_BANDBORDERS)
  203.         x += g_cxEdge;
  204.     return x;
  205. }
  206. void RBRealize(PRB prb, HDC hdcParam, BOOL fBackground, BOOL fForceRepaint)
  207. {
  208.     if (prb->hpal)
  209.     {
  210.         HDC hdc = hdcParam ? hdcParam : GetDC(prb->ci.hwnd);
  211.         if (hdc)
  212.         {
  213.             BOOL fRepaint;
  214.             
  215.             SelectPalette(hdc, prb->hpal, fBackground);
  216.             fRepaint = RealizePalette(hdc) || fForceRepaint;
  217.             if (!hdcParam)
  218.                 ReleaseDC(prb->ci.hwnd, hdc);
  219.             if (fRepaint)
  220.             {
  221.                 InvalidateRect(prb->ci.hwnd, NULL, TRUE);
  222.             }
  223.         }
  224.     }
  225. }
  226. //////////////////////////////////////////////////////////////////
  227. // RBSendNotify
  228. //
  229. // sends a wm_notify of code iCode and packages up all the data for you
  230. // for band uBand
  231. //
  232. //////////////////////////////////////////////////////////////////
  233. LRESULT RBSendNotify(PRB prb, UINT uBand, int iCode)
  234. {
  235.     NMREBAR nm = {0};
  236.     
  237.     nm.uBand = uBand;
  238.     if (uBand != (UINT)-1) {
  239.         nm.dwMask = RBNM_ID | RBNM_STYLE | RBNM_LPARAM;
  240.         nm.wID = RBGETBAND(prb, uBand)->wID;
  241.         nm.fStyle = RBGETBAND(prb, uBand)->fStyle;
  242.         nm.lParam = RBGETBAND(prb, uBand)->lParam;
  243.     }
  244.     return CCSendNotify(&prb->ci, iCode, &nm.hdr);
  245. }
  246. BOOL RBInvalidateRect(PRB prb, RECT* prc)
  247. {
  248.     if (prb->fRedraw) 
  249.     {
  250.         RECT rc;
  251.         if (prc && RB_ISVERT(prb))
  252.         {
  253.             CopyRect(&rc, prc);
  254.             FlipRect(&rc);
  255.             prc = &rc;
  256.         }
  257.         prb->fRefreshPending = FALSE;
  258.         InvalidateRect(prb->ci.hwnd, prc, TRUE);
  259.         return TRUE;
  260.     }
  261.     else 
  262.     {
  263.         prb->fRefreshPending = TRUE;
  264.         return FALSE;
  265.     }
  266. }
  267. LRESULT RebarDragCallback(HWND hwnd, UINT code, WPARAM wp, LPARAM lp)
  268. {
  269.     PRB prb = (PRB)GetWindowPtr(hwnd, 0);
  270.     LRESULT lres;
  271.     switch (code)
  272.     {
  273.     case DPX_DRAGHIT:
  274.         if (lp)
  275.         {
  276.             int iBand;
  277.             RBHITTESTINFO rbht;
  278.             rbht.pt.x = ((POINTL *)lp)->x;
  279.             rbht.pt.y = ((POINTL *)lp)->y;
  280.             MapWindowPoints(NULL, prb->ci.hwnd, &rbht.pt, 1);
  281.             iBand = RBHitTest(prb, &rbht);
  282.             *(DWORD*)wp = rbht.flags;
  283.             lres = (LRESULT)(iBand != -1 ? prb->rbbList[iBand].wID : -1);
  284.         }
  285.         else
  286.             lres = -1;
  287.         break;
  288.     case DPX_GETOBJECT:
  289.         lres = (LRESULT)GetItemObject(&prb->ci, RBN_GETOBJECT, &IID_IDropTarget, (LPNMOBJECTNOTIFY)lp);
  290.         break;
  291.     default:
  292.         lres = -1;
  293.         break;
  294.     }
  295.     return lres;
  296. }
  297. // ----------------------------------------------------------------------------
  298. //
  299. // RBCanBandMove
  300. //
  301. // returns TRUE if the given band can be moved and FALSE if it cannot
  302. //
  303. // ----------------------------------------------------------------------------
  304. BOOL  RBCanBandMove(PRB prb, PRBB prbb)
  305. {
  306.     // If there is only one visible band it cannot move
  307.     if (RBEnumBand(prb, 1, RBBS_HIDDEN) > RB_GETLASTBAND(prb))
  308.         return FALSE;
  309.     ASSERT(!(prbb->fStyle & RBBS_HIDDEN));
  310.         
  311.     if ((prb->ci.style & RBS_FIXEDORDER)
  312.       && (prbb == RBEnumBand(prb, 0, RBBS_HIDDEN)))
  313.         // the first (visible) band in fixed order rebars can't be moved
  314.         return(FALSE);
  315.     
  316.     // fixed size bands can't be moved
  317.     return(!(prbb->fStyle & RBBS_FIXEDSIZE));
  318. }
  319. // ----------------------------------------------------------------------------
  320. //
  321. // RBBCalcMinWidth
  322. //
  323. // calculates minimum width for the given band
  324. //
  325. // ----------------------------------------------------------------------------
  326. void  RBBCalcMinWidth(PRB prb, PRBB prbb)
  327. {
  328.     BOOL fDrawGripper = RBShouldDrawGripper(prb, prbb);
  329.     BOOL fVertical;
  330.     int  cEdge;
  331.     BOOL fEmpty = ((prbb->iImage == -1) && (!RBSHOWTEXT(prbb)));
  332.     if (prbb->fStyle & RBBS_HIDDEN) {
  333.         ASSERT(0);
  334.         return;
  335.     }
  336.     // did the user specify the size explicitly?
  337.     if (prbb->fStyle & RBBS_FIXEDHEADERSIZE)
  338.         return;
  339.     prbb->cxMin = prbb->cxMinChild;
  340.     if (RBBUSECHEVRON(prb, prbb))
  341.         prbb->cxMin += CX_CHEVRON;
  342.     if (!fDrawGripper && fEmpty)
  343.         return;
  344.     fVertical = (prb->ci.style & CCS_VERT);
  345.     if (RB_ISVERTICALGRIPPER(prb)) {
  346.         
  347.         prbb->cxMin += 4 * g_cyEdge;
  348.         prbb->cxMin += max(prb->cyImage, prb->cyFont);
  349.         
  350.     } else {
  351.         cEdge = fVertical ? g_cyEdge : g_cxEdge;
  352.         prbb->cxMin += 2 * cEdge;
  353.         if (fDrawGripper)
  354.         {
  355.             prbb->cxMin += RB_GRABWIDTH * (fVertical ? g_cyBorder : g_cxBorder);
  356.             if (fEmpty)
  357.                 return;
  358.         }
  359.         prbb->cxMin += 2 * cEdge;
  360.         if (prbb->iImage != -1)
  361.             prbb->cxMin += (fVertical ? prb->cyImage : prb->cxImage);
  362.         if (RBSHOWTEXT(prbb))
  363.         {
  364.             if (fVertical)
  365.                 prbb->cxMin += prb->cyFont;
  366.             else
  367.                 prbb->cxMin += prbb->cxText;
  368.             if (prbb->iImage != -1)
  369.                 // has both image and text -- add in edge between 'em
  370.                 prbb->cxMin += cEdge;
  371.         }
  372.     }
  373. }
  374. BOOL RBShouldDrawGripper(PRB prb, PRBB prbb)
  375. {
  376.     if (prbb->fStyle & RBBS_NOGRIPPER)
  377.         return FALSE;
  378.     if ((prbb->fStyle & RBBS_GRIPPERALWAYS) || RBCanBandMove(prb, prbb))
  379.         return TRUE;
  380.     
  381.     return FALSE;
  382.         
  383. }
  384. // ----------------------------------------------------------------------------
  385. //
  386. // RBBCalcTextExtent
  387. //
  388. // computes the horizontal extent of the given band's title text in the current
  389. // title font for the rebar
  390. //
  391. // returns TRUE if text extent changed, FALSE otherwise
  392. //
  393. // ----------------------------------------------------------------------------
  394. BOOL  RBBCalcTextExtent(PRB prb, PRBB prbb, HDC hdcIn)
  395. {
  396.     HDC     hdc = hdcIn;
  397.     HFONT   hFontOld;
  398.     UINT    cx;
  399.     if (prbb->fStyle & RBBS_HIDDEN)
  400.     {
  401.         ASSERT(0);      // caller should have skipped
  402.         return FALSE;
  403.     }
  404.     if (!RBSHOWTEXT(prbb))
  405.     {
  406.         cx = 0;
  407.     }
  408.     else
  409.     {
  410.         if (!hdcIn && !(hdc = GetDC(prb->ci.hwnd)))
  411.             return FALSE;
  412.         hFontOld = SelectObject(hdc, prb->hFont);
  413.         // for clients >= v5, we draw text with prefix processing (& underlines next char)
  414.         if (prb->ci.iVersion >= 5)
  415.         {
  416.             RECT rc = {0,0,0,0};
  417.             DrawText(hdc, prbb->lpText, lstrlen(prbb->lpText), &rc, DT_CALCRECT);
  418.             cx = RECTWIDTH(rc);
  419.         }
  420.         else
  421.         {
  422.             SIZE size;
  423.             GetTextExtentPoint(hdc, prbb->lpText, lstrlen(prbb->lpText), &size);
  424.             cx = size.cx;
  425.         }
  426.         SelectObject(hdc, hFontOld);
  427.         if (!hdcIn)
  428.             ReleaseDC(prb->ci.hwnd, hdc);
  429.     }
  430.     if (prbb->cxText != cx)
  431.     {
  432.         prbb->cxText = cx;
  433.         RBBCalcMinWidth(prb, prbb);
  434.         return TRUE;
  435.     }
  436.     return FALSE;
  437. }
  438. // ----------------------------------------------------------------------------
  439. //
  440. // RBBGetHeight
  441. //
  442. // returns minimum height for the given band
  443. // TODO: make this a field in the band structure instead of always calling this
  444. //
  445. // ----------------------------------------------------------------------------
  446. UINT  RBBGetHeight(PRB prb, PRBB prbb)
  447. {
  448.     UINT cy = 0;
  449.     BOOL fVertical = (prb->ci.style & CCS_VERT);
  450.     UINT cyCheck, cyBorder;
  451.     cyBorder = (fVertical ? g_cxEdge : g_cyEdge) * 2;
  452.     if (prbb->hwndChild)
  453.     {
  454.         cy = prbb->cyChild;
  455.         if (!(prbb->fStyle & RBBS_CHILDEDGE))
  456.             // add edge to top and bottom of child window
  457.             cy -= cyBorder;
  458.     }
  459.     if (RBSHOWTEXT(prbb) && !fVertical)
  460.     {
  461.         cyCheck = prb->cyFont;
  462.         if (cyCheck > cy)
  463.             cy = cyCheck;
  464.     }
  465.     if (prbb->iImage != -1)
  466.     {
  467.         cyCheck = (fVertical) ? prb->cxImage : prb->cyImage;
  468.         if (cyCheck > cy)
  469.             cy = cyCheck;
  470.     }
  471.     return(cy + cyBorder);
  472. }
  473. // ----------------------------------------------------------------------------
  474. //
  475. // RBGetRowCount
  476. //
  477. // returns the number of rows in the rebar's current configuration
  478. //
  479. // ----------------------------------------------------------------------------
  480. UINT  RBGetRowCount(PRB prb)
  481. {
  482.     UINT i;
  483.     UINT cRows = 0;
  484.     for (i = 0; i < prb->cBands; i++) {
  485.         if (RBGETBAND(prb, i)->fStyle & RBBS_HIDDEN)
  486.             continue;
  487.         if (RBISSTARTOFROW(prb, i))
  488.             cRows++;
  489.     }
  490.     return(cRows);
  491. }
  492. // ----------------------------------------------------------------------------
  493. //
  494. // RBGetLineHeight
  495. //
  496. // returns the height of the line of bands from iStart to iEnd, inclusively
  497. //
  498. // ----------------------------------------------------------------------------
  499. UINT  RBGetLineHeight(PRB prb, UINT iStart, UINT iEnd)
  500. {
  501.     UINT cy = 0;
  502.     PRBB prbb;
  503.     UINT cyBand;
  504.     if (!(prb->ci.style & RBS_VARHEIGHT))
  505.     {
  506.         // for fixed height bars, line height is maximum height of ALL bands
  507.         iStart = 0;
  508.         iEnd = prb->cBands - 1;
  509.     }
  510.     for (prbb = prb->rbbList + iStart; iStart <= iEnd; prbb++, iStart++)
  511.     {
  512.         if (prbb->fStyle & RBBS_HIDDEN)
  513.             continue;
  514.         cyBand = RBBGetHeight(prb, prbb);
  515.         cy = max(cy, cyBand);
  516.     }
  517.     return(cy);
  518. }
  519. // RBRecalcChevron: update & refresh chevron
  520. void RBRecalcChevron(PRB prb, PRBB prbb, BOOL fChevron)
  521. {
  522.     RECT rcChevron;
  523.     if (fChevron)
  524.     {
  525.         rcChevron.right = prbb->x + prbb->cx;
  526.         rcChevron.left = rcChevron.right - CX_CHEVRON;
  527.         rcChevron.top = prbb->y;
  528.         rcChevron.bottom = rcChevron.top + prbb->cy;
  529.     }
  530.     else
  531.         SetRect(&rcChevron, -1, -1, -1, -1);
  532.     if (!EqualRect(&rcChevron, &prbb->rcChevron))
  533.     {
  534.         if (prbb->fChevron)
  535.             RBInvalidateRect(prb, &prbb->rcChevron);
  536.         prbb->fChevron = fChevron;
  537.         CopyRect(&prbb->rcChevron, &rcChevron);
  538.         if (prbb->fChevron)
  539.             RBInvalidateRect(prb, &prbb->rcChevron);
  540.     }
  541. }
  542. // ----------------------------------------------------------------------------
  543. //
  544. // RBResizeChildren
  545. //
  546. // resizes children to fit properly in their respective bands' bounding rects
  547. //
  548. // ----------------------------------------------------------------------------
  549. void  RBResizeChildren(PRB prb)
  550. {
  551.     int     cx, cy, x, y, cxHeading;
  552.     HDWP    hdwp;
  553.     BOOL    fVertical = (prb->ci.style & CCS_VERT);
  554.     PRBB prbb, prbbEnd;
  555.     if (!prb->cBands || !prb->fRedraw)
  556.         return;
  557.     hdwp = BeginDeferWindowPos(prb->cBands);
  558.     prbb = RBGETBAND(prb, 0);
  559.     prbbEnd = RB_GETLASTBAND(prb);
  560.     for ( ; prbb <= prbbEnd ; prbb++)
  561.     {
  562.         NMREBARCHILDSIZE nm;
  563.         BOOL fChevron = FALSE;
  564.         if (prbb->fStyle & RBBS_HIDDEN)
  565.             continue;
  566.         
  567.         if (!prbb->hwndChild)
  568.             continue;
  569.         cxHeading = RBBHEADERWIDTH(prbb);
  570.         x = prbb->x + cxHeading;
  571.         cx = prbb->cx - cxHeading;
  572.         // if we're not giving child ideal size, make space for chevron button
  573.         if ((cx < prbb->cxIdeal) && RBBUSECHEVRON(prb, prbb))
  574.         {
  575.             fChevron = TRUE;
  576.             cx -= CX_CHEVRON;
  577.         }
  578.         if (!(prbb->fStyle & RBBS_FIXEDSIZE)) {
  579.             if (fVertical) {
  580.                 PRBB prbbNext = RBBNextVisible(prb, prbb);
  581.                 if (prbbNext && !RBISBANDSTARTOFROW(prbbNext))
  582.                     cx -= g_cyEdge * 2;
  583.             } else 
  584.                 cx -= CX_OFFSET;
  585.         }
  586.         if (cx < 0)
  587.             cx = 0;
  588.         y = prbb->y;
  589.         cy = prbb->cy;
  590.         if (prbb->cyChild && (prbb->cyChild < (UINT) cy))
  591.         {
  592.             y += (cy - prbb->cyChild) / 2;
  593.             cy = prbb->cyChild;
  594.         }
  595.         nm.rcChild.left = x;
  596.         nm.rcChild.top = y;
  597.         nm.rcChild.right = x + cx;
  598.         nm.rcChild.bottom = y + cy;
  599.         nm.rcBand.left = prbb->x + RBBHEADERWIDTH(prbb);
  600.         nm.rcBand.right = prbb->x + prbb->cx;
  601.         nm.rcBand.top = prbb->y;
  602.         nm.rcBand.bottom = prbb->y + prbb->cy;
  603.         nm.uBand = RBBANDTOINDEX(prb, prbb);
  604.         nm.wID = prbb->wID;
  605.         if (fVertical) {
  606.             FlipRect(&nm.rcChild);
  607.             FlipRect(&nm.rcBand);
  608.         }
  609.         
  610.         CCSendNotify(&prb->ci, RBN_CHILDSIZE, &nm.hdr);
  611.         if (!RB_ISVALIDBAND(prb, prbb)) {
  612.             // somebody responded to notify by nuking bands; bail
  613.             break;
  614.         }
  615.         RBRecalcChevron(prb, prbb, fChevron);
  616.         DeferWindowPos(hdwp, prbb->hwndChild, NULL, nm.rcChild.left, nm.rcChild.top, 
  617.                        RECTWIDTH(nm.rcChild), RECTHEIGHT(nm.rcChild), SWP_NOZORDER);
  618.     }
  619.     EndDeferWindowPos(hdwp);
  620.     //
  621.     //  The SQL 7.0 Enterprise Manager Data Transformation Services MMC Snap-In
  622.     //  (and the Visual Basic Coolbar Sample App, too) is stupid.
  623.     //  It hosts a rebar but doesn't set the WS_CLIPCHILDREN flag,
  624.     //  so when it erases its background, it wipes out the rebar.  So don't
  625.     //  call UpdateWindow() here, or we will paint *first*, then SQL will
  626.     //  erase us by mistake.  We have to leave our paint pending, so that
  627.     //  when SQL erases us by mistake, we will eventually get a WM_PAINT
  628.     //  message afterwards.
  629.     //
  630. #if 0
  631.     UpdateWindow(prb->ci.hwnd);
  632. #endif
  633. }
  634. // ----------------------------------------------------------------------------
  635. //
  636. // RBMoveBand
  637. //
  638. // moves the band from one position to another in the rebar's band array,
  639. // updating the rebar's iCapture field as needed
  640. //
  641. // returns TRUE or FALSE if something moved
  642. // ----------------------------------------------------------------------------
  643. BOOL  RBMoveBand(PRB prb, UINT iFrom, UINT iTo)
  644. {
  645.     RBB rbbMove;
  646.     int iShift;
  647.     BOOL fCaptureChanged = (prb->iCapture == -1);
  648.     if (iFrom != iTo)
  649.     {
  650.         rbbMove = *RBGETBAND(prb, iFrom);
  651.         if (prb->iCapture == (int) iFrom)
  652.         {
  653.             prb->iCapture = (int) iTo;
  654.             fCaptureChanged = TRUE;
  655.         }
  656.         iShift = (iFrom > iTo) ? -1 : 1;
  657.         while (iFrom != iTo)
  658.         {
  659.             if (!fCaptureChanged && (prb->iCapture == (int) (iFrom + iShift)))
  660.             {
  661.                 prb->iCapture = (int) iFrom;
  662.                 fCaptureChanged = TRUE;
  663.             }
  664.             *RBGETBAND(prb, iFrom) = *RBGETBAND(prb, iFrom + iShift);
  665.             iFrom += iShift;
  666.         }
  667.         *RBGETBAND(prb, iTo) = rbbMove;
  668.         return TRUE;
  669.     }
  670.     return(FALSE);
  671. }
  672. // ----------------------------------------------------------------------------
  673. //
  674. // RBRecalc
  675. //
  676. // recomputes bounding rects for all bands in given rebar
  677. //
  678. // ----------------------------------------------------------------------------
  679. UINT  RBRecalc(PRB prb)
  680. {
  681.     PRBB    prbb = RBGETBAND(prb, 0);
  682.     PRBB    prbbWalk;
  683.     UINT    cHidden;    // # of hidden guys we've seen in current row
  684.     UINT    cxRow;
  685.     UINT    cxMin;
  686.     UINT    i;
  687.     UINT    j;
  688.     UINT    k;
  689.     UINT    iFixed = 0xFFFF;
  690.     int     cy;
  691.     int     y;
  692.     int     x;
  693.     UINT    cxBar;
  694.     RECT    rc;
  695.     HWND    hwndSize;
  696.     BOOL    fNewLine = FALSE;
  697.     BOOL    fChanged;
  698.     BOOL    fVertical = (prb->ci.style & CCS_VERT);
  699.     BOOL    fBandBorders;
  700.     int     iBarWidth;
  701.     if (!prb->cBands)
  702.         return(0);
  703.     if ((prb->ci.style & CCS_NORESIZE) || (prb->ci.style & CCS_NOPARENTALIGN))
  704.         // size based on rebar window itself
  705.         hwndSize = prb->ci.hwnd;
  706.     else if (!(hwndSize = prb->ci.hwndParent))
  707.         // size based on parent window -- if no parent window, bail now
  708.         return(0);
  709.     if (!prb->fRecalc) {
  710.         // defer this recalc
  711.         prb->fRecalcPending = TRUE;
  712.         return 0;
  713.     } else {
  714.         prb->fRecalcPending = FALSE;
  715.     }
  716.     GetClientRect(hwndSize, &rc);
  717.     iBarWidth = (fVertical ? (rc.bottom - rc.top) : (rc.right - rc.left));
  718.     // this can happen because we adjust the client rect, but wedon't change 
  719.     // the getminmaxinfo.
  720.     if (iBarWidth <= 0)
  721.         iBarWidth = 1;
  722.     cxBar = (UINT) iBarWidth;    
  723.     fBandBorders = (prb->ci.style & RBS_BANDBORDERS);
  724.     for (i = 0; i < prb->cBands; i++) {
  725.         prb->rbbList[i].cx = prb->rbbList[i].cxRequest;
  726.     }
  727.     y = 0;
  728.     i = 0;
  729.     // Main Loop -- loop until all bands are calculated
  730.     while (i < prb->cBands)
  731.     {
  732.         TraceMsg(TF_REBAR, "RBRecalc: outer loop i=%d", i);
  733.         
  734.         if (fBandBorders && (y > 0))
  735.             y += g_cyEdge;
  736. ReLoop:
  737.         cxRow = 0;
  738.         cxMin = 0;
  739.         x = 0;
  740.         cHidden = 0;
  741.         // Row Loop -- loop until hard line break is found or soft line break
  742.         // is necessary
  743.         for (j = i, prbbWalk = prbb; j < prb->cBands; j++, prbbWalk++)
  744.         {
  745.             TraceMsg(TF_REBAR, "RBRecalc: inner loop j=%d", j);
  746.             
  747.             if (prbbWalk->fStyle & RBBS_HIDDEN) {
  748.                 ++cHidden;
  749.                 continue;
  750.             }
  751.             if (j > i + cHidden)
  752.             {
  753.                 // not the first band in the row -- check for break style
  754.                 if ((prbbWalk->fStyle & RBBS_BREAK) && !(prbbWalk->fStyle & RBBS_FIXEDSIZE))
  755.                     break;
  756.                 if (fBandBorders)
  757.                     // add in space for vertical etch on palettized display
  758.                     cxMin += g_cxEdge;
  759.             }
  760.             if (prbbWalk->fStyle & RBBS_FIXEDSIZE)
  761.             {
  762.                 // remember location of branding brick
  763.                 iFixed = j;
  764.              
  765.                 // if this is the first band, the next band cannot have a forced break.
  766.                 if (i + cHidden == j) {
  767.                     // if the first index in the row (i) plus the number of hidden items (cHidden) leaves us at this band,
  768.                     // then it's the first visible in this row.
  769.                     PRBB prbbNextVis = RBBNextVisible(prb, prbbWalk);
  770.                     if (prbbNextVis && (prbbNextVis->fStyle & RBBS_BREAK)) {
  771.                         // can't do this unilaterally because on startup
  772.                         // some folks (net meeting) initialize it in reverse order
  773.                         // and we whack off this break bit incorrectly
  774.                         if (prb->fRedraw && IsWindowVisible(prb->ci.hwnd))
  775.                             prbbNextVis->fStyle &= ~RBBS_BREAK;
  776.                     }
  777.                 }
  778.                 
  779.                 prbbWalk->cx = prbbWalk->cxMin;
  780.             }
  781.             if (prbbWalk->cx < prbbWalk->cxMin)
  782.                 prbbWalk->cx = prbbWalk->cxMin;
  783.             cxMin += prbbWalk->cxMin; // update running total of min widths
  784.             // read the assert comment below
  785.             if (j > i + cHidden)
  786.             {
  787.                 // not the first band in row -- check for need to autobreak
  788.                 if (cxMin > cxBar)
  789.                     // autobreak here
  790.                     break;
  791.                 if (fBandBorders)
  792.                     // add in space for vertical etch on palettized display
  793.                     cxRow += g_cxEdge;
  794.             }
  795.             cxRow += prbbWalk->cx; // update running total of current widths
  796.         }
  797.         if (!i)
  798.         {
  799.             // first row -- handle proper placement of branding band
  800.             if (iFixed == 0xFFFF)
  801.             {
  802.                 // branding band not yet found; look in the remaining bands
  803.                 k = j;
  804.                 for ( ; j < prb->cBands; j++)
  805.                 {
  806.                     if (RBGETBAND(prb, j)->fStyle & RBBS_HIDDEN)
  807.                         continue;
  808.                     if (RBGETBAND(prb, j)->fStyle & RBBS_FIXEDSIZE)
  809.                     {
  810.                         // branding band found; move to 1st row and recompute
  811.                         ASSERT(j != k);                        
  812.                         RBMoveBand(prb, j, k);
  813.                         goto ReLoop;
  814.                     }
  815.                 }
  816.                 // no branding band found -- reset j and continue on
  817.                 j = k;
  818.             }
  819.             else
  820.                 // we have a branding band; move it to
  821.                 // the rightmost position in the row
  822.                 RBMoveBand(prb, iFixed, j - 1);
  823.             TraceMsg(TF_REBAR, "RBRecalc: after brand i=%d", i);            
  824.         }
  825.         // variant:
  826.         // now the current row of bands is from i to j - 1
  827.         // n.b. i (and some following bands) might be hidden
  828.         // assert that j != i because then the above variant won't be true
  829.         ASSERT(j != i);     // BUGBUG RBBS_HIDDEN?
  830.         if (cxRow > cxBar)
  831.         {
  832.             // bands are too long -- shrink bands from right to left
  833.             for (k = i; k < j; k++)
  834.             {
  835.                 prbbWalk--;
  836.                 if (prbbWalk->fStyle & RBBS_HIDDEN)
  837.                     continue;
  838.                 if (prbbWalk->cx > prbbWalk->cxMin)
  839.                 {
  840.                     cxRow -= prbbWalk->cx - prbbWalk->cxMin;
  841.                     prbbWalk->cx = prbbWalk->cxMin;
  842.                     if (cxRow <= cxBar)
  843.                     {
  844.                         prbbWalk->cx += cxBar - cxRow;
  845.                         break;
  846.                     }
  847.                 }
  848.             }
  849.             TraceMsg(TF_REBAR, "RBRecalc: after shrink i=%d", i);            
  850.         }
  851.         else if (cxRow < cxBar)
  852.         {
  853.             // bands are too short -- grow rightmost non-minimized band
  854.             for (k = j - 1; k >= i; k--)
  855.             {
  856.                 ASSERT(k != (UINT)-1);  // catch infinite loop
  857.                 prbbWalk--;
  858.                 if ((k == i) || 
  859.                     (!(prbbWalk->fStyle & (RBBS_HIDDEN | RBBS_FIXEDSIZE)) &&
  860.                      (prbbWalk->cx > prbb->cxMin)))
  861.                 {
  862.                     // the k == i check  means we've made it to the first
  863.                     // band on this row and so he has to get the cx change
  864.                     if (prbbWalk->fStyle & RBBS_HIDDEN) 
  865.                     {
  866.                         ASSERT(k == i);
  867.                         prbbWalk = RBBNextVisible(prb, prbbWalk);
  868.                         if (!prbbWalk)
  869.                             break;
  870.                     }
  871.                     prbbWalk->cx += cxBar - cxRow;
  872.                     break;
  873.                 }
  874.             }
  875.             TraceMsg(TF_REBAR, "RBRecalc: after grow i=%d", i);            
  876.         }
  877.         // items from index i to index j-1 (inclusive) WILL fit on one line
  878.         cy = RBGetLineHeight(prb, i, j - 1);
  879.         fChanged = FALSE; // set if any bands on current row changed position
  880.         for ( ; i < j; i++, prbb++)
  881.         {
  882.             if (prbb->fStyle & RBBS_HIDDEN)
  883.                 continue;
  884.             // go through row of bands, updating positions and heights,
  885.             // invalidating as needed
  886.             if ((prbb->y != y) || (prbb->x != x) || (prbb->cy != cy))
  887.             {
  888.                 TraceMsg(TF_REBAR, "RBRecalc: invalidate i=%d", RBBANDTOINDEX(prb, prbb));
  889.                 fChanged = TRUE;
  890.                 rc.left = min(prbb->x, x);
  891.                 rc.top = min(prbb->y, y);
  892.                 rc.right = cxBar;
  893.                 rc.bottom = max(prbb->y + prbb->cy, y + cy);
  894.                 if (fBandBorders)
  895.                 {
  896.                     // acount for etch line that will need to move
  897.                     rc.left -= g_cxEdge;
  898.                     rc.bottom += g_cyEdge/2;
  899.                 }
  900.                 RBInvalidateRect(prb, &rc);
  901.             }
  902.             prbb->x = x;
  903.             prbb->y = y;
  904.             prbb->cy = cy;
  905.             x += RBBANDWIDTH(prb, prbb);
  906.         }
  907.         // i and prbb now refer to the first band in the next row of bands
  908.         y += cy;
  909.     }
  910.     prb->cy = y;
  911.     return(y);
  912. }
  913. // ----------------------------------------------------------------------------
  914. //
  915. // RBResize
  916. //
  917. // recomputes bounding rects for all bands and then resizes rebar and children
  918. // based on these rects
  919. //
  920. // ----------------------------------------------------------------------------
  921. void  RBResizeNow(PRB prb)
  922. {
  923.     RECT rc;
  924.     BOOL bMirroredWnd=(prb->ci.dwExStyle&RTL_MIRRORED_WINDOW);
  925.     if (!prb || !prb->ci.hwndParent)
  926.         return;
  927.     GetWindowRect(prb->ci.hwnd, &rc);
  928.     //
  929.     // If this is a mirrored window, we don't won't to refect the
  930.     // coordinates since they are coming from the screen coord
  931.     // which they are not mirrored. [samera]
  932.     //
  933.     if (bMirroredWnd)
  934.         MapRectInRTLMirroredWindow(&rc, prb->ci.hwndParent);
  935.     else 
  936.         MapWindowPoints(HWND_DESKTOP, prb->ci.hwndParent, (LPPOINT)&rc, 2);
  937.     RBResizeChildren(prb);
  938.     NewSize(prb->ci.hwnd, prb->cy, prb->ci.style, rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc));
  939.     if (prb->fResizeNotify) 
  940.         CCSendNotify(&prb->ci, RBN_HEIGHTCHANGE, NULL);
  941.     prb->fResizeNotify = FALSE;
  942.     prb->fResizePending = FALSE;
  943. }
  944. void  RBResize(PRB prb, BOOL fForceHeightChange)
  945. {
  946.     UINT cy;
  947. StartOver:
  948.     // lots of the code relies on having cy calculated synchronously with RBResize,
  949.     // but we're going to delay the actual changing of the window
  950.     cy = prb->cy;
  951.     if (prb->fResizing)
  952.     {
  953.         prb->fResizeRecursed = TRUE;
  954.         return;
  955.     }
  956.     prb->fResizing = TRUE;
  957.     
  958.     RBRecalc(prb);    
  959.    // true overrides always
  960.     if (fForceHeightChange || (cy != prb->cy))
  961.         prb->fResizeNotify = TRUE;
  962.     if (prb->fRedraw) {
  963.         RBResizeNow(prb);
  964.     } else 
  965.         prb->fResizePending = TRUE;
  966.         
  967.     prb->fResizing = FALSE;
  968.     
  969.     // we do this to avoid infinite loop...  RBResize can cause NewSize which causes 
  970.     // a notify in which the parent sizes us, which causes us to loop.
  971.     // if the parent does any message pumping during the NewSize, we're in a loop 
  972.     if (prb->fResizeRecursed) {
  973.         prb->fResizeRecursed = FALSE;
  974.         fForceHeightChange = FALSE;
  975.         goto StartOver;
  976.     }     
  977. }
  978. void RBSetRecalc(PRB prb, BOOL fRecalc)
  979. {
  980.     prb->fRecalc = fRecalc;
  981.     if (fRecalc) {
  982.         if (prb->fRecalcPending)
  983.             RBRecalc(prb);
  984.     }
  985. }
  986. BOOL RBSetRedraw(PRB prb, BOOL fRedraw)
  987. {
  988.     BOOL fOld = prb->fRedraw;
  989.     if (prb) {
  990.         prb->fRedraw = BOOLIFY(fRedraw);
  991.         if (fRedraw) {
  992.             // save off prb->fRefreshPending since this can
  993.             // get changed by call to RBResizeNow
  994.             BOOL fRefreshPending = prb->fRefreshPending;
  995.             if (prb->fResizePending)
  996.                 RBResizeNow(prb);
  997.             if (fRefreshPending)
  998.                 RBInvalidateRect(prb, NULL);
  999.         }
  1000.     }
  1001.     
  1002.     return fOld;
  1003. }
  1004. BOOL RBAfterSetFont(PRB prb)
  1005. {
  1006.     TEXTMETRIC tm;
  1007.     BOOL fChange = FALSE;
  1008.     UINT        i;
  1009.     HFONT hOldFont;
  1010.     
  1011.     HDC hdc = GetDC(prb->ci.hwnd);
  1012.     if (!hdc)
  1013.         return FALSE;
  1014.     hOldFont = SelectObject(hdc, prb->hFont);
  1015.     GetTextMetrics(hdc, &tm);
  1016.     if (prb->cyFont != (UINT) tm.tmHeight)
  1017.     {
  1018.         prb->cyFont = tm.tmHeight;
  1019.         fChange = TRUE;
  1020.     }
  1021.     // adjust bands
  1022.     for (i = 0; i < prb->cBands; i++)
  1023.     {
  1024.         if (RBGETBAND(prb, i)->fStyle & RBBS_HIDDEN)
  1025.             continue;
  1026.         fChange |= RBBCalcTextExtent(prb, RBGETBAND(prb, i), hdc);
  1027.     }
  1028.     SelectObject(hdc, hOldFont);
  1029.     ReleaseDC(prb->ci.hwnd, hdc);
  1030.     if (fChange)
  1031.     {
  1032.         RBResize(prb, FALSE);
  1033.         // invalidate, o.w. title doesn't redraw 1st time after font growth
  1034.         RBInvalidateRect(prb, NULL);
  1035.     }
  1036.     return TRUE;
  1037. }
  1038. BOOL RBOnSetFont(PRB prb, HFONT hFont)
  1039. {
  1040.     if (prb->fFontCreated) {
  1041.         DeleteObject(prb->hFont);
  1042.     }
  1043.     
  1044.     prb->hFont = hFont;
  1045.     prb->fFontCreated = FALSE;
  1046.     if (!prb->hFont)
  1047.         RBSetFont(prb, 0);
  1048.     else 
  1049.         return RBAfterSetFont(prb);
  1050.     
  1051.     return TRUE;
  1052. }
  1053. // ----------------------------------------------------------------------------
  1054. //
  1055. // RBSetFont
  1056. //
  1057. // sets the rebar band title font to the current system-wide caption font
  1058. //
  1059. // ----------------------------------------------------------------------------
  1060. BOOL  RBSetFont(PRB prb, WPARAM wParam)
  1061. {
  1062.     NONCLIENTMETRICS ncm;
  1063.     HFONT hOldFont;
  1064.     if ((wParam != 0) && (wParam != SPI_SETNONCLIENTMETRICS))
  1065.         return(FALSE);
  1066.     ncm.cbSize = sizeof(NONCLIENTMETRICS);
  1067.     if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0))
  1068.         return(FALSE);
  1069.     hOldFont = prb->hFont;
  1070.     ncm.lfCaptionFont.lfWeight = FW_NORMAL;
  1071.     if (!(prb->hFont = CreateFontIndirect(&ncm.lfCaptionFont)))
  1072.     {
  1073.         prb->hFont = hOldFont;
  1074.         return(FALSE);
  1075.     }
  1076.     prb->fFontCreated = TRUE;
  1077.     if (hOldFont)
  1078.         DeleteObject(hOldFont);
  1079.     
  1080.     return RBAfterSetFont(prb);
  1081. }
  1082. // ----------------------------------------------------------------------------
  1083. //
  1084. //  Draws a horizontal or vertical dotted line from the given (x,y) location
  1085. //  for the given length (c). (From TReeView's TV_DrawDottedLine)
  1086. //
  1087. // ----------------------------------------------------------------------------
  1088. void RBVertMungeGripperRect(PRB prb, LPRECT lprc)
  1089. {
  1090.     if (RB_ISVERTICALGRIPPER(prb)) {
  1091.         OffsetRect(lprc, -lprc->left + lprc->top, -lprc->top + lprc->left);
  1092.         lprc->bottom -= g_cyEdge;
  1093.     } else {
  1094.         FlipRect(lprc);
  1095.     }
  1096. }
  1097. void RBDrawChevron(PRB prb, PRBB prbb, HDC hdc)
  1098. {
  1099.     RECT rc;
  1100.     DWORD dwFlags = prbb->wChevState | DCHF_HORIZONTAL | DCHF_TRANSPARENT;
  1101.     CopyRect(&rc, &prbb->rcChevron);
  1102.     if (RB_ISVERT(prb))
  1103.         FlipRect(&rc);
  1104.     else
  1105.         dwFlags |= DCHF_TOPALIGN;
  1106.     DrawChevron(hdc, &rc, dwFlags);
  1107. }
  1108. void RBUpdateChevronState(PRB prb, PRBB prbb, WORD wControlState)
  1109. {
  1110.     if (!prb || !prbb)
  1111.         return;
  1112.     // if no change in state, bail
  1113.     if (!(wControlState ^ prbb->wChevState))
  1114.         return;
  1115.     prbb->wChevState = wControlState;
  1116.     // if active (pushed or hottracked)
  1117.     if (!(wControlState & DCHF_INACTIVE)) {
  1118.         // then we're now the hot band
  1119.         prb->prbbHot = prbb;
  1120.     }
  1121.     // else if we were the hot band then clear
  1122.     else if (prbb == prb->prbbHot) {
  1123.         prb->prbbHot = NULL;
  1124.     }
  1125.     // clear background & repaint
  1126.     RBInvalidateRect(prb, &prbb->rcChevron);
  1127.     UpdateWindow(prb->ci.hwnd);
  1128. }
  1129. // ----------------------------------------------------------------------------
  1130. //
  1131. // RBDrawBand
  1132. //
  1133. // draws the title icon and title text of the given band into the given DC;
  1134. // also the band's chevron
  1135. //
  1136. // ----------------------------------------------------------------------------
  1137. void  RBDrawBand(PRB prb, PRBB prbb, HDC hdc)
  1138. {
  1139.     int                 xStart, yCenter;
  1140.     COLORREF            clrBackSave, clrForeSave;
  1141.     int                 iModeSave;
  1142.     BOOL                fVertical = RB_ISVERT(prb);
  1143.     BOOL                fDrawHorizontal = (!fVertical || RB_ISVERTICALGRIPPER(prb));
  1144.     NMCUSTOMDRAW        nmcd;
  1145.     LRESULT             dwRet;
  1146.     if (prbb->fStyle & RBBS_HIDDEN) {
  1147.         ASSERT(0);
  1148.         return;
  1149.     }
  1150.     clrForeSave = SetTextColor(hdc, RBB_GetTextColor(prb, prbb));
  1151.     clrBackSave = SetBkColor(hdc, RBB_GetBkColor(prb, prbb));
  1152.     if (prbb->hbmBack)
  1153.         iModeSave = SetBkMode(hdc, TRANSPARENT);
  1154.     nmcd.hdc = hdc;
  1155.     nmcd.dwItemSpec = prbb->wID;
  1156.     nmcd.uItemState = 0;
  1157.     nmcd.lItemlParam = prbb->lParam;
  1158.     nmcd.rc.top = prbb->y;
  1159.     nmcd.rc.left = prbb->x;
  1160.     nmcd.rc.bottom = nmcd.rc.top + prbb->cy;
  1161.     nmcd.rc.right = nmcd.rc.left + RBBHEADERWIDTH(prbb);
  1162.     if (prb->ci.style & CCS_VERT)
  1163.     {
  1164.         FlipRect(&nmcd.rc);
  1165.     }
  1166. #ifdef KEYBOARDCUES
  1167. #if 0
  1168.     // BUGBUG: Custom draw stuff for UISTATE (stephstm)
  1169.     if (CCGetUIState(&(prb->ci), KC_TBD))
  1170.         nmcd.uItemState |= CDIS_SHOWKEYBOARDCUES;
  1171. #endif
  1172. #endif
  1173.     dwRet = CICustomDrawNotify(&prb->ci, CDDS_ITEMPREPAINT, &nmcd);
  1174.     if (!(dwRet & CDRF_SKIPDEFAULT))
  1175.     {
  1176.         int cy;
  1177.         
  1178.         if (RB_ISVERTICALGRIPPER(prb)) {
  1179.             cy = RBBHEADERWIDTH(prbb);
  1180.             yCenter = prbb->x + (cy / 2);
  1181.         } else {
  1182.             cy = prbb->cy;
  1183.             yCenter = prbb->y + (cy / 2);
  1184.         }
  1185.         xStart = prbb->x;
  1186.         if (RBShouldDrawGripper(prb, prbb))
  1187.         {
  1188.             RECT rc;
  1189.             int  c;
  1190.             int dy;
  1191.             c = 3 * g_cyBorder;
  1192.             xStart += 2 * g_cxBorder;
  1193.             dy = g_cxEdge;
  1194.             SetRect(&rc, xStart, prbb->y + dy, xStart + c, prbb->y + cy - dy);
  1195.             if (fVertical)
  1196.             {
  1197.                 RBVertMungeGripperRect(prb, &rc);
  1198.                 if (RB_ISVERTICALGRIPPER(prb))
  1199.                     xStart = rc.left;
  1200.             }
  1201.             CCDrawEdge(hdc, &rc, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE, &(prb->clrsc));
  1202.             xStart += c;
  1203.         }
  1204.         xStart += 2 * (fVertical ? g_cyEdge : g_cxEdge);
  1205.         if (prbb->iImage != -1)
  1206.         { 
  1207.             UINT                yStart;
  1208.             IMAGELISTDRAWPARAMS imldp = {0};
  1209.             yStart = yCenter - ((!fDrawHorizontal ? prb->cxImage : prb->cyImage) / 2);
  1210.             imldp.cbSize = sizeof(imldp);
  1211.             imldp.himl   = prb->himl;
  1212.             imldp.i      = prbb->iImage;
  1213.             imldp.hdcDst = hdc;
  1214.             imldp.x      = (!fDrawHorizontal ? yStart : xStart);
  1215.             imldp.y      = (!fDrawHorizontal ? xStart : yStart);
  1216.             imldp.rgbBk  = CLR_DEFAULT;
  1217.             imldp.rgbFg  = CLR_DEFAULT;
  1218.             imldp.fStyle = ILD_TRANSPARENT;
  1219.             ImageList_DrawIndirect(&imldp);
  1220.             xStart +=  (fDrawHorizontal ? (prb->cxImage + g_cxEdge) : (prb->cyImage + g_cyEdge));
  1221.         }
  1222.         if (RBSHOWTEXT(prbb))
  1223.         {
  1224.             HFONT hFontSave = SelectObject(hdc, prb->hFont);
  1225.             RECT rcText;
  1226.             
  1227.             rcText.left = fDrawHorizontal ? xStart : yCenter - (prbb->cxText / 2);
  1228.             rcText.top = fDrawHorizontal ? yCenter - (prb->cyFont / 2) : xStart;
  1229.             if (fDrawHorizontal)
  1230.                 rcText.top -= 1;    // fudge
  1231.             rcText.right = rcText.left + prbb->cxText;
  1232.             rcText.bottom = rcText.top + prb->cyFont;
  1233.             // for clients >= v5, we draw text with prefix processing (& underlines next char)
  1234.             if (prb->ci.iVersion >= 5)
  1235.             {
  1236.                 UINT uFormat=0;
  1237. #ifdef KEYBOARDCUES
  1238.                 if (CCGetUIState(&(prb->ci)) & UISF_HIDEACCEL)
  1239.                    uFormat= DT_HIDEPREFIX;
  1240. #endif
  1241.                 DrawText(hdc, prbb->lpText, lstrlen(prbb->lpText), &rcText, uFormat);
  1242.             }
  1243.             else
  1244.                 TextOut(hdc, rcText.left, rcText.top, prbb->lpText, lstrlen(prbb->lpText));
  1245.             SelectObject(hdc, hFontSave);
  1246.         }
  1247.         // maybe draw chevron
  1248.         if (RBBUSECHEVRON(prb, prbb) && prbb->fChevron)
  1249.             RBDrawChevron(prb, prbb, hdc);
  1250.     }
  1251.     if (dwRet & CDRF_NOTIFYPOSTPAINT)
  1252.         CICustomDrawNotify(&prb->ci, CDDS_ITEMPOSTPAINT, &nmcd);
  1253.     if (prbb->hbmBack)
  1254.         SetBkMode(hdc, iModeSave);
  1255.     SetTextColor(hdc, clrForeSave);
  1256.     SetBkColor(hdc, clrBackSave);
  1257. }
  1258. // ----------------------------------------------------------------------------
  1259. //
  1260. // RBPaint
  1261. //
  1262. // processes WM_PAINT message
  1263. //
  1264. // ----------------------------------------------------------------------------
  1265. void  RBPaint(PRB prb, HDC hdcIn)
  1266. {
  1267.     HDC         hdc = hdcIn;
  1268.     PAINTSTRUCT ps;
  1269.     UINT        i;
  1270.     NMCUSTOMDRAW    nmcd;
  1271.     if (!hdcIn)
  1272.         hdc = BeginPaint(prb->ci.hwnd, &ps);
  1273.     else
  1274.         GetClientRect(prb->ci.hwnd, &ps.rcPaint);
  1275.     nmcd.hdc = hdc;
  1276.     nmcd.uItemState = 0;
  1277.     nmcd.lItemlParam = 0;
  1278.     nmcd.rc = ps.rcPaint;
  1279.     prb->ci.dwCustom = CICustomDrawNotify(&prb->ci, CDDS_PREPAINT, &nmcd);
  1280.     if (!(prb->ci.dwCustom & CDRF_SKIPDEFAULT))
  1281.     {
  1282.         for (i = 0; i < prb->cBands; i++) {
  1283.             if (RBGETBAND(prb, i)->fStyle & RBBS_HIDDEN)
  1284.                 continue;
  1285.             RBDrawBand(prb, RBGETBAND(prb, i), hdc);
  1286.         }
  1287.     }
  1288.     if (prb->ci.dwCustom & CDRF_NOTIFYPOSTPAINT)
  1289.         CICustomDrawNotify(&prb->ci, CDDS_POSTPAINT, &nmcd);
  1290.     if (!hdcIn)
  1291.         EndPaint(prb->ci.hwnd, &ps);
  1292. }
  1293. // ----------------------------------------------------------------------------
  1294. //
  1295. // RBTileBlt
  1296. //
  1297. // Fills the given rectangle with the rebar's background bitmap, tiling if
  1298. // necessary
  1299. //
  1300. // ----------------------------------------------------------------------------
  1301. void  RBTileBlt(PRB prb, PRBB prbb, UINT x, UINT y, UINT cx, UINT cy, HDC hdcDst, HDC hdcSrc)
  1302. {
  1303.     UINT xOff = 0;
  1304.     UINT yOff = 0;
  1305.     BOOL fxTile, fyTile;
  1306.     int cxPart, cyPart;
  1307.     int iPixelOffset = 0;
  1308. #ifndef WINNT
  1309.     // On Win98 BiDi, Bitblt has off-by-one bug in mirroring
  1310.     if(IS_DC_RTL_MIRRORED(hdcSrc))
  1311.     {
  1312.         iPixelOffset = 1;
  1313.     }
  1314. #endif // WINNT
  1315.     if (!(prbb->fStyle & RBBS_FIXEDBMP))
  1316.     {
  1317.         if (prb->ci.style & CCS_VERT)
  1318.         {
  1319.             xOff = -prbb->y;
  1320.             yOff = -prbb->x;
  1321.         }
  1322.         else
  1323.         {
  1324.             xOff = -prbb->x;
  1325.             yOff = -prbb->y;
  1326.         }
  1327.     }
  1328.     xOff += x;
  1329.     if (xOff >= prbb->cxBmp)
  1330.         xOff %= prbb->cxBmp;
  1331.     yOff += y;
  1332.     if (yOff >= prbb->cyBmp)
  1333.         yOff %= prbb->cyBmp;
  1334. ReCheck:
  1335.     fxTile = ((xOff + cx) > prbb->cxBmp);
  1336.     fyTile = ((yOff + cy) > prbb->cyBmp);
  1337.     if (!fxTile && !fyTile)
  1338.     {
  1339.         // no tiling needed -- blt and leave
  1340.         BitBlt(hdcDst, x , y, cx, cy, hdcSrc, xOff + iPixelOffset, yOff, SRCCOPY);
  1341.         return;
  1342.     }
  1343.     if (!fxTile)
  1344.     {
  1345.         // vertically tile
  1346.         cyPart = prbb->cyBmp - yOff;
  1347.         BitBlt(hdcDst, x, y, cx, cyPart, hdcSrc, xOff + iPixelOffset, yOff, SRCCOPY);
  1348.         y += cyPart;
  1349.         cy -= cyPart;
  1350.         yOff = 0;
  1351.         goto ReCheck;
  1352.     }
  1353.     if (!fyTile)
  1354.     {
  1355.         // horizontally tile
  1356.         cxPart = prbb->cxBmp - xOff;
  1357.         BitBlt(hdcDst, x, y, cxPart, cy, hdcSrc, xOff + iPixelOffset, yOff, SRCCOPY);
  1358.         x += cxPart;
  1359.         cx -= cxPart;
  1360.         xOff = 0;
  1361.         goto ReCheck;
  1362.     }
  1363.     // tile both ways
  1364.     cyPart = prbb->cyBmp - yOff;
  1365.     RBTileBlt(prb, prbb, x, y, cx, cyPart, hdcDst, hdcSrc);
  1366.     y += cyPart;
  1367.     cy -= cyPart;
  1368.     yOff = 0;
  1369.     goto ReCheck;
  1370. }
  1371. // this is using virtual coordinate space (internal always horizontal)
  1372. int _RBHitTest(PRB prb, LPRBHITTESTINFO prbht, int x, int y)
  1373. {
  1374.     BOOL fVert = (prb->ci.style & CCS_VERT);
  1375.     int i;
  1376.     PRBB prbb = RBGETBAND(prb, 0);
  1377.     int  cx;
  1378.     RBHITTESTINFO rbht;
  1379.     
  1380.     if (!prbht)
  1381.         prbht = &rbht;
  1382.     for (i = 0; i < (int) prb->cBands; i++, prbb++)
  1383.     {
  1384.         if (prbb->fStyle & RBBS_HIDDEN)
  1385.             continue;
  1386.         if ((x >= prbb->x) && (y >= prbb->y) &&
  1387.             (x <= (prbb->x + prbb->cx)) && (y <= (prbb->y + prbb->cy)))
  1388.         {
  1389.             cx = RBBHEADERWIDTH(prbb);
  1390.             if (x <= (int) (prbb->x + cx))
  1391.             {
  1392.                 prbht->flags = RBHT_CAPTION;
  1393.                 
  1394.                 if (RB_ISVERTICALGRIPPER(prb)) {
  1395.                     if (y - prbb->y < RB_GRABWIDTH)
  1396.                         prbht->flags = RBHT_GRABBER;
  1397.                 } else {
  1398.                     cx = RB_GRABWIDTH * (fVert ? g_cyBorder : g_cxBorder);
  1399.                     if (RBShouldDrawGripper(prb, RBGETBAND(prb, i)) &&
  1400.                         (x <= (int) (prbb->x + cx)))
  1401.                         prbht->flags = RBHT_GRABBER;
  1402.                 }
  1403.             }
  1404.             else
  1405.             {
  1406.                 POINT pt;
  1407.                 pt.x = x;
  1408.                 pt.y = y;
  1409.                 if (RBBUSECHEVRON(prb, prbb) && prbb->fChevron && PtInRect(&prbb->rcChevron, pt))
  1410.                     prbht->flags = RBHT_CHEVRON;
  1411.                 else
  1412.                     prbht->flags = RBHT_CLIENT;
  1413.             }
  1414.             prbht->iBand = i;
  1415.             return(i);
  1416.             break;
  1417.         }
  1418.     }
  1419.     prbht->flags = RBHT_NOWHERE;
  1420.     prbht->iBand = -1;
  1421.     return(-1);
  1422. }
  1423. // ----------------------------------------------------------------------------
  1424. //
  1425. // RBHitTest
  1426. //
  1427. // returns the index to the band that the given point lies in, or -1 if outside
  1428. // of all bands.  Also, sets flags to indicate which part of the band the
  1429. // point lies in.
  1430. //
  1431. // ----------------------------------------------------------------------------
  1432. int RBHitTest(PRB prb, LPRBHITTESTINFO prbht)
  1433. {
  1434.     BOOL fVert = (prb->ci.style & CCS_VERT);
  1435.     POINT pt;
  1436.     if (fVert)
  1437.     {
  1438.         pt.x = prbht->pt.y;
  1439.         pt.y = prbht->pt.x;
  1440.     }
  1441.     else
  1442.         pt = prbht->pt;
  1443.     
  1444.     return _RBHitTest(prb, prbht, pt.x, pt.y);
  1445. }
  1446. // ----------------------------------------------------------------------------
  1447. //
  1448. // RBEraseBkgnd
  1449. //
  1450. // processes WM_ERASEBKGND message by drawing band borders, if necessary, and
  1451. // filling in the rebar bands with their background color
  1452. //
  1453. // ----------------------------------------------------------------------------
  1454. BOOL  RBEraseBkgnd(PRB prb, HDC hdc, int iBand)
  1455. {
  1456.     BOOL fVertical = (prb->ci.style & CCS_VERT);
  1457.     NMCUSTOMDRAW    nmcd;
  1458.     LRESULT         dwItemRet;
  1459.     BOOL            fBandBorders;
  1460.     RECT            rcClient;
  1461.     HDC             hdcMem = NULL;
  1462.     UINT            i;
  1463.     PRBB            prbb = RBGETBAND(prb, 0);
  1464.     nmcd.hdc = hdc;
  1465.     nmcd.uItemState = 0;
  1466.     nmcd.lItemlParam = 0;
  1467.     prb->ci.dwCustom = CICustomDrawNotify(&prb->ci, CDDS_PREERASE, &nmcd);
  1468.     if (!(prb->ci.dwCustom & CDRF_SKIPDEFAULT))
  1469.     {
  1470.         COLORREF clrBk;
  1471.         fBandBorders = (prb->ci.style & RBS_BANDBORDERS);
  1472.         GetClientRect(prb->ci.hwnd, &rcClient);
  1473.         clrBk = RB_GetBkColor(prb);
  1474.         if (clrBk != CLR_NONE) {
  1475.             FillRectClr(hdc, &rcClient, clrBk);
  1476.         }
  1477.         for (i = 0; i < prb->cBands; i++, prbb++)
  1478.         {
  1479.             if (prbb->fStyle & RBBS_HIDDEN)
  1480.                 continue;
  1481.             if (fVertical)
  1482.                 SetRect(&nmcd.rc, prbb->y, prbb->x, prbb->y + prbb->cy, prbb->x + prbb->cx);
  1483.             else
  1484.                 SetRect(&nmcd.rc, prbb->x, prbb->y, prbb->x + prbb->cx, prbb->y + prbb->cy);
  1485.             if (fBandBorders)
  1486.             {
  1487.                 if (prbb->x)
  1488.                 {
  1489.                     // draw etch between bands on same row
  1490.                     if (fVertical)
  1491.                     {
  1492.                         nmcd.rc.right += g_cxEdge / 2;
  1493.                         nmcd.rc.top -= g_cyEdge;
  1494.                         CCDrawEdge(hdc, &nmcd.rc, EDGE_ETCHED, BF_TOP, &(prb->clrsc));
  1495.                         nmcd.rc.right -= g_cxEdge / 2;
  1496.                         nmcd.rc.top += g_cyEdge;
  1497.                     }
  1498.                     else
  1499.                     {
  1500.                         nmcd.rc.bottom += g_cyEdge / 2;
  1501.                         nmcd.rc.left -= g_cxEdge;
  1502.                         CCDrawEdge(hdc, &nmcd.rc, EDGE_ETCHED, BF_LEFT, &(prb->clrsc));
  1503.                         nmcd.rc.bottom -= g_cyEdge / 2;
  1504.                         nmcd.rc.left += g_cxEdge;
  1505.                     }
  1506.                 }
  1507.                 else
  1508.                 {
  1509.                     // draw etch between rows
  1510.                     if (fVertical)
  1511.                     {
  1512.                         rcClient.right = prbb->y + prbb->cy + g_cxEdge;
  1513.                         CCDrawEdge(hdc, &rcClient, EDGE_ETCHED, BF_RIGHT, &(prb->clrsc));
  1514.                     }
  1515.                     else
  1516.                     {
  1517.                         rcClient.bottom = prbb->y + prbb->cy + g_cyEdge;
  1518.                         CCDrawEdge(hdc, &rcClient, EDGE_ETCHED, BF_BOTTOM, &(prb->clrsc));
  1519.                     }
  1520.                 }
  1521.             }
  1522.             nmcd.dwItemSpec = prbb->wID;
  1523.             nmcd.uItemState = 0;
  1524.             dwItemRet = CICustomDrawNotify(&prb->ci, CDDS_ITEMPREERASE, &nmcd);
  1525.             if (!(dwItemRet & CDRF_SKIPDEFAULT))
  1526.             {
  1527.                 if (prbb->hbmBack)
  1528.                 {
  1529.                     if (!hdcMem)
  1530.                     {
  1531.                         if (!(hdcMem = CreateCompatibleDC(hdc)))
  1532.                             continue;
  1533.                         RBRealize(prb, hdc, TRUE, FALSE);
  1534.                     }
  1535.                     SelectObject(hdcMem, prbb->hbmBack);
  1536.                     RBTileBlt(prb, prbb, nmcd.rc.left, nmcd.rc.top, nmcd.rc.right - nmcd.rc.left,
  1537.                             nmcd.rc.bottom - nmcd.rc.top, hdc, hdcMem);
  1538.                 }
  1539.                 else
  1540.                 {
  1541.                     // if the color for this band is the same as the 
  1542.                     // rebar's default background color, then we
  1543.                     // don't need to paint this specially
  1544.                     COLORREF clr = RBB_GetBkColor(prb, prbb);
  1545.                     if (clr != RB_GetBkColor(prb)) {
  1546.                         FillRectClr(hdc, &nmcd.rc, clr);
  1547.                     }
  1548.                 }
  1549.             }
  1550.             if (dwItemRet & CDRF_NOTIFYPOSTERASE)
  1551.                 CICustomDrawNotify(&prb->ci, CDDS_ITEMPOSTERASE, &nmcd);
  1552.         }
  1553.         if (hdcMem)
  1554.         {
  1555.             DeleteDC(hdcMem);
  1556.         }
  1557.     }
  1558.     if (prb->ci.dwCustom & CDRF_NOTIFYPOSTERASE)
  1559.     {
  1560.         nmcd.uItemState = 0;
  1561.         nmcd.dwItemSpec = 0;
  1562.         nmcd.lItemlParam = 0;
  1563.         CICustomDrawNotify(&prb->ci, CDDS_POSTERASE, &nmcd);
  1564.     }
  1565.     return(TRUE);
  1566. }
  1567. // ----------------------------------------------------------------------------
  1568. //
  1569. // RBGetBarInfo
  1570. //
  1571. // retrieves the indicated values from the rebar's internal structure
  1572. //
  1573. // ----------------------------------------------------------------------------
  1574. BOOL  RBGetBarInfo(PRB prb, LPREBARINFO lprbi)
  1575. {
  1576.     if (!prb || (lprbi->cbSize != sizeof(REBARINFO)))
  1577.         return(FALSE);
  1578.     if (lprbi->fMask & RBIM_IMAGELIST)
  1579.         lprbi->himl = prb->himl;
  1580.     return(TRUE);
  1581. }
  1582. // ----------------------------------------------------------------------------
  1583. //
  1584. // RBSetBarInfo
  1585. //
  1586. // sets the indicated values in the rebar's internal structure, recalculating
  1587. // and refreshing as needed
  1588. //
  1589. // ----------------------------------------------------------------------------
  1590. BOOL  RBSetBarInfo(PRB prb, LPREBARINFO lprbi)
  1591. {
  1592.     if (!prb || (lprbi->cbSize != sizeof(REBARINFO)))
  1593.         return(FALSE);
  1594.     if (lprbi->fMask & RBIM_IMAGELIST)
  1595.     {
  1596.         HIMAGELIST himl = prb->himl;
  1597.         UINT    cxOld, cyOld;
  1598.         //todo:validate lprbi->himl
  1599.         prb->himl = lprbi->himl;
  1600.         cxOld = prb->cxImage;
  1601.         cyOld = prb->cyImage;
  1602.         ImageList_GetIconSize(prb->himl, (LPINT)&prb->cxImage, (LPINT)&prb->cyImage);
  1603.         if ((prb->cxImage != cxOld) || (prb->cyImage != cyOld))
  1604.         {
  1605.             UINT i;
  1606.             for (i = 0; i < prb->cBands; i++) {
  1607.                 if (RBGETBAND(prb, i)->fStyle & RBBS_HIDDEN)
  1608.                     continue;
  1609.                 RBBCalcMinWidth(prb, RBGETBAND(prb, i));
  1610.             }
  1611.             RBResize(prb, FALSE);
  1612.         }
  1613.         else
  1614.             RBInvalidateRect(prb, NULL);
  1615.         lprbi->himl = himl;
  1616.     }
  1617.     return(TRUE);
  1618. }
  1619. // ----------------------------------------------------------------------------
  1620. //
  1621. // RBGetBandInfo
  1622. //
  1623. // retrieves the indicated values from the specified band's internal structure
  1624. //
  1625. // ----------------------------------------------------------------------------
  1626. BOOL  RBGetBandInfo(PRB prb, UINT uBand, LPREBARBANDINFO lprbbi)
  1627. {
  1628.     PRBB prbb;
  1629.     if (!prb || (!RB_ISVALIDINDEX(prb, uBand)) || (lprbbi->cbSize > SIZEOF(REBARBANDINFO)))
  1630.         return(FALSE);
  1631.     prbb = RBGETBAND(prb, uBand);
  1632.     if (lprbbi->fMask & RBBIM_SIZE) {
  1633.         if (prbb->fStyle & RBBS_FIXEDSIZE)
  1634.             lprbbi->cx = prbb->cx;
  1635.         else 
  1636.             lprbbi->cx = prbb->cxRequest;
  1637.     }
  1638.     
  1639.     if (lprbbi->fMask & RBBIM_HEADERSIZE) 
  1640.         lprbbi->cxHeader = RBBHEADERWIDTH(prbb);
  1641.     
  1642.     if (lprbbi->fMask & RBBIM_IDEALSIZE)
  1643.         // HACKHACK: (tjgreen) Subtract the offset we added in SetBandInfo (see 
  1644.         // comments there).
  1645.         lprbbi->cxIdeal = prbb->cxIdeal ? prbb->cxIdeal - CX_OFFSET : 0;
  1646.     if (lprbbi->fMask & RBBIM_STYLE)
  1647.         lprbbi->fStyle = prbb->fStyle;
  1648.     if (lprbbi->fMask & RBBIM_COLORS)
  1649.     {
  1650.         lprbbi->clrFore = RBB_GetTextColor_External(prb, prbb);
  1651.         lprbbi->clrBack = RBB_GetBkColor_External(prb, prbb);
  1652.     }
  1653.     if (lprbbi->fMask & RBBIM_TEXT)
  1654.     {
  1655.         UINT cch = prbb->lpText ? lstrlen(prbb->lpText) : 0;
  1656.         if (!lprbbi->cch || !lprbbi->lpText || (lprbbi->cch <= cch))
  1657.             lprbbi->cch = cch + 1;
  1658.         else if (prbb->lpText)
  1659.             lstrcpy(lprbbi->lpText, prbb->lpText);
  1660.         else
  1661.             // no text -- so just make it an empty string
  1662.             lprbbi->lpText[0] = 0;
  1663.     }
  1664.     if (lprbbi->fMask & RBBIM_IMAGE)
  1665.         lprbbi->iImage = prbb->iImage;
  1666.     if (lprbbi->fMask & RBBIM_CHILD)
  1667.         lprbbi->hwndChild = prbb->hwndChild;
  1668.     if (lprbbi->fMask & RBBIM_CHILDSIZE)
  1669.     {
  1670.         // HACKHACK: (tjgreen) Subtract the offset we added in SetBandInfo (see
  1671.         // comments there).
  1672.         lprbbi->cxMinChild = prbb->cxMinChild ? prbb->cxMinChild - CX_OFFSET : 0;
  1673.         lprbbi->cyMinChild = prbb->cyMinChild;
  1674.         
  1675.         if (prbb->fStyle & RBBS_VARIABLEHEIGHT) {
  1676.             lprbbi->cyIntegral = prbb->cyIntegral;
  1677.             lprbbi->cyMaxChild = prbb->cyMaxChild;
  1678.             lprbbi->cyChild = prbb->cyChild;
  1679.         }
  1680.     }
  1681.     if (lprbbi->fMask & RBBIM_BACKGROUND)
  1682.         lprbbi->hbmBack = prbb->hbmBack;
  1683.     if (lprbbi->fMask & RBBIM_ID)
  1684.         lprbbi->wID = prbb->wID;
  1685.     if (lprbbi->fMask & RBBIM_LPARAM)
  1686.         lprbbi->lParam = prbb->lParam;
  1687.     return(TRUE);
  1688. }
  1689. BOOL RBValidateBandInfo(LPREBARBANDINFO *pprbbi, LPREBARBANDINFO prbbi)
  1690. {
  1691.     BOOL fRet = ((*pprbbi)->cbSize == sizeof(REBARBANDINFO));
  1692.     
  1693.     if (!fRet) {
  1694.         
  1695.         if ((*pprbbi)->cbSize < SIZEOF(REBARBANDINFO)) {
  1696.             hmemcpy(prbbi, (*pprbbi), (*pprbbi)->cbSize);
  1697.             (*pprbbi) = prbbi;
  1698.             prbbi->cbSize = SIZEOF(REBARBANDINFO);
  1699.             fRet = TRUE;
  1700.         }
  1701.     }
  1702.     return fRet;
  1703. }
  1704. // ----------------------------------------------------------------------------
  1705. //
  1706. // RBSetBandInfo
  1707. //
  1708. // sets the indicated values in the specified band's internal structure,
  1709. // recalculating and refreshing as needed
  1710. //
  1711. // ----------------------------------------------------------------------------
  1712. BOOL  RBSetBandInfo(PRB prb, UINT uBand, LPREBARBANDINFO lprbbi, BOOL fAllowRecalc)
  1713. {
  1714.     PRBB    prbb;
  1715.     BOOL    fRefresh = FALSE;
  1716.     BOOL    fRecalc  = FALSE;
  1717.     BOOL    fRecalcMin = FALSE;
  1718.     BOOL    fTextChanged = FALSE;
  1719.     REBARBANDINFO rbbi = {0};
  1720.     RECT    rc;
  1721.     if (!prb || (!RB_ISVALIDINDEX(prb, uBand)) || 
  1722.         !RBValidateBandInfo(&lprbbi, &rbbi))
  1723.         return(FALSE);
  1724.     prbb = RBGETBAND(prb, uBand);
  1725.     if (lprbbi->fMask & RBBIM_TEXT)
  1726.     {
  1727.         if (!lprbbi->lpText || !prbb->lpText || lstrcmp(lprbbi->lpText, prbb->lpText))
  1728.         {
  1729.             if (lprbbi->lpText != prbb->lpText) {
  1730.                 Str_Set(&prbb->lpText, lprbbi->lpText);
  1731.                 fTextChanged = TRUE;
  1732.             }
  1733.         }
  1734.     }
  1735.     if (lprbbi->fMask & RBBIM_STYLE)
  1736.     {
  1737.         UINT fStylePrev = prbb->fStyle;
  1738.         UINT fChanged = lprbbi->fStyle ^ fStylePrev;
  1739.         prbb->fStyle = lprbbi->fStyle;
  1740.         if (fChanged)
  1741.             fRecalc = TRUE;
  1742.         if ((prbb->fStyle & RBBS_FIXEDSIZE) && !(fStylePrev & RBBS_FIXEDSIZE))
  1743.             prbb->cxMin = prbb->cx;
  1744.         else if (fChanged & RBBS_FIXEDSIZE)
  1745.             fRecalcMin = TRUE;
  1746.         
  1747.         if (fChanged & RBBS_GRIPPERALWAYS)
  1748.             fRecalcMin = TRUE;
  1749.         
  1750.         if (fChanged & RBBS_HIDDEN) 
  1751.             RBShowBand(prb, uBand, !(prbb->fStyle & RBBS_HIDDEN));
  1752.         if (fChanged & RBBS_HIDETITLE)
  1753.             fTextChanged = TRUE;
  1754.         // can't have both of these
  1755.         if (prbb->fStyle & RBBS_FIXEDSIZE)
  1756.             prbb->fStyle &= ~RBBS_BREAK;
  1757.         
  1758.     }
  1759.     // RBBIM_TEXT does calculations that want to take some RBBIM_STYLE bits
  1760.     // into account, so delay those calculations until we grab the style bits.
  1761.     //
  1762.     if (fTextChanged && !(prbb->fStyle & RBBS_HIDDEN))
  1763.     {
  1764.         if (RBBCalcTextExtent(prb, prbb, NULL))
  1765.             fRecalc = TRUE;
  1766.         else
  1767.             fRefresh = TRUE;
  1768.     }
  1769.     if (lprbbi->fMask & RBBIM_IDEALSIZE)
  1770.     {
  1771.         // HACKHACK: (tjgreen) Add an offset to the width the caller specifies.
  1772.         // This offset gets clipped off in RBResizeChildren, so the child window is  
  1773.         // rendered with the width specified by caller, and we get a little space on 
  1774.         // the toolbar after the buttons.  If caller specifies zero-width, though, 
  1775.         // we don't want this extra space, so don't add offset.
  1776.         int cxIdeal = lprbbi->cxIdeal ? lprbbi->cxIdeal + CX_OFFSET : 0;
  1777.         if (cxIdeal != prbb->cxIdeal) {
  1778.             prbb->cxIdeal = cxIdeal;
  1779.             fRecalcMin = TRUE;
  1780.             fRecalc = TRUE;
  1781.         }
  1782.     }
  1783.     
  1784.     if (lprbbi->fMask & RBBIM_SIZE)
  1785.     {
  1786.         if (prbb->cxRequest != (int) lprbbi->cx)
  1787.         {
  1788.             fRecalc = TRUE;
  1789.             prbb->cxRequest = (int) lprbbi->cx;
  1790.         }
  1791.         if (prbb->fStyle & RBBS_FIXEDSIZE)
  1792.             prbb->cxMin = prbb->cxRequest;
  1793.     }
  1794.     
  1795.     if (lprbbi->fMask & RBBIM_HEADERSIZE)
  1796.     {
  1797.         if ((lprbbi->cxHeader == -1) ||
  1798.             !(prbb->fStyle & RBBS_FIXEDHEADERSIZE) ||
  1799.             ((UINT)prbb->cxMin != lprbbi->cxHeader + prbb->cxMinChild)) {
  1800.             if (lprbbi->cxHeader == -1) {
  1801.                 prbb->fStyle &= ~RBBS_FIXEDHEADERSIZE;
  1802.                 fRecalcMin = TRUE;
  1803.             } else {
  1804.                 prbb->fStyle |= RBBS_FIXEDHEADERSIZE;
  1805.                 prbb->cxMin = lprbbi->cxHeader + prbb->cxMinChild;
  1806.             }
  1807.             fRecalc = TRUE;
  1808.             fRefresh = TRUE;
  1809.         }
  1810.     }
  1811.     if (lprbbi->fMask & RBBIM_COLORS)
  1812.     {
  1813.         prbb->clrFore = lprbbi->clrFore;
  1814.         prbb->clrBack = lprbbi->clrBack;
  1815.         fRefresh = TRUE;
  1816.     }
  1817.     if ((lprbbi->fMask & RBBIM_IMAGE) && (prbb->iImage != lprbbi->iImage))
  1818.     {
  1819.         BOOL fToggleBmp = ((prbb->iImage == -1) || (lprbbi->iImage == -1));
  1820.         prbb->iImage = lprbbi->iImage;
  1821.         if (fToggleBmp)
  1822.         {
  1823.             fRecalc = TRUE;
  1824.             fRecalcMin = TRUE;
  1825.         }
  1826.         else
  1827.             fRefresh = TRUE;
  1828.     }
  1829.     if (lprbbi->fMask & RBBIM_CHILD &&
  1830.         lprbbi->hwndChild != prbb->hwndChild &&
  1831.         (NULL == lprbbi->hwndChild || 
  1832.          !IsChild(lprbbi->hwndChild, prb->ci.hwnd)))
  1833.     {
  1834.         if (IsWindow(prbb->hwndChild))
  1835.             ShowWindow(prbb->hwndChild, SW_HIDE);        
  1836.         prbb->hwndChild = lprbbi->hwndChild;
  1837.         if (prbb->hwndChild)
  1838.         {
  1839.             SetParent(prbb->hwndChild, prb->ci.hwnd);
  1840.             ShowWindow(prbb->hwndChild, SW_SHOW);
  1841.         }
  1842.         fRecalc = TRUE;
  1843.     }
  1844.     if (lprbbi->fMask & RBBIM_CHILDSIZE)
  1845.     {
  1846.         UINT cyChildOld = prbb->cyChild;
  1847.         if (lprbbi->cyMinChild != -1)
  1848.             prbb->cyMinChild = lprbbi->cyMinChild;
  1849.         if (prbb->fStyle & RBBS_VARIABLEHEIGHT) {
  1850.             
  1851.             if (lprbbi->cyIntegral != -1)
  1852.                 prbb->cyIntegral = lprbbi->cyIntegral;
  1853.             
  1854.             if (lprbbi->cyMaxChild != -1)
  1855.                 prbb->cyMaxChild = lprbbi->cyMaxChild;
  1856.             
  1857.             if (lprbbi->cyChild != -1)
  1858.                 prbb->cyChild = lprbbi->cyChild;
  1859.             if (prbb->cyChild < prbb->cyMinChild)
  1860.                 prbb->cyChild = prbb->cyMinChild;
  1861.             if (prbb->cyChild > prbb->cyMaxChild)
  1862.                 prbb->cyChild = prbb->cyMaxChild;
  1863.             // validate the child size.  cyChild must be cyMinChild plux n*cyIntegral
  1864.             if (prbb->cyIntegral) {
  1865.                 int iExtra;
  1866.                 iExtra = (prbb->cyChild - prbb->cyMinChild) % prbb->cyIntegral;
  1867.                 prbb->cyChild -= iExtra;
  1868.             }
  1869.             
  1870.         } else {
  1871.             // if we're not in variable height mode, then 
  1872.             // the cyChild is the same as cyMinChild.  
  1873.             // this is a little peculiar, but done this way for backcompat.
  1874.             // cyMinChild came before cyChild
  1875.             prbb->cyChild = lprbbi->cyMinChild;
  1876.         }
  1877.         if (lprbbi->cxMinChild != (UINT)-1) {
  1878.             // HACKHACK: (tjgreen) Add an offset to the width the caller specifies.
  1879.             // This offset gets clipped off in RBResizeChildren, so the child window is  
  1880.             // rendered with the width specified by caller, and we get a little space on 
  1881.             // the toolbar after the buttons.  However, if caller specifies zero-width or
  1882.             // if the band is fixed size, we don't want this extra space, so don't add offset.
  1883.             UINT cxMinChild = lprbbi->cxMinChild;
  1884.             if ((lprbbi->cxMinChild != 0) && !(prbb->fStyle & RBBS_FIXEDSIZE))
  1885.                 cxMinChild += CX_OFFSET;
  1886.             if (prbb->cxMinChild != cxMinChild) {
  1887.                 int cxOldHeaderMin = RBBHEADERWIDTH(prbb);
  1888.                 
  1889.                 if (prbb->fStyle & RBBS_FIXEDSIZE)
  1890.                     fRecalc = TRUE;
  1891.                     
  1892.                 prbb->cxMinChild = cxMinChild;
  1893.                 
  1894.                 if (prbb->fStyle & RBBS_FIXEDHEADERSIZE)
  1895.                     prbb->cxMin = cxOldHeaderMin + prbb->cxMinChild;
  1896.                 
  1897.                 fRecalcMin = TRUE;
  1898.             }
  1899.             
  1900.             if (cyChildOld != prbb->cyChild) {
  1901.                 // TODO:  revisit optimization:
  1902.                 // if (RBBGetHeight(prb, prbb) != (UINT) prbb->cy)
  1903.                 fRecalc = TRUE;
  1904.             }
  1905.         }
  1906.             
  1907.     }
  1908.     if (lprbbi->fMask & RBBIM_BACKGROUND)
  1909.     {
  1910.         DIBSECTION  dib;
  1911.         if (lprbbi->hbmBack && !GetObject(lprbbi->hbmBack, sizeof(DIBSECTION), &dib))
  1912.             return(FALSE);
  1913.         prbb->hbmBack = lprbbi->hbmBack;
  1914.         prbb->cxBmp = dib.dsBm.bmWidth;
  1915.         prbb->cyBmp = dib.dsBm.bmHeight;
  1916.         fRefresh = TRUE;
  1917.     }
  1918.     if (lprbbi->fMask & RBBIM_ID)
  1919.         prbb->wID = lprbbi->wID;
  1920.     if (lprbbi->fMask & RBBIM_LPARAM)
  1921.         prbb->lParam = lprbbi->lParam;
  1922.     if (fRecalcMin && !(prbb->fStyle & RBBS_HIDDEN))
  1923.         RBBCalcMinWidth(prb, prbb);
  1924.     if (fAllowRecalc) {
  1925.         if (fRecalc)
  1926.             RBResize(prb, FALSE);
  1927.         if (fRefresh || fRecalc)
  1928.         {
  1929.             // '|| fRecalc' so we catch add/grow of text.
  1930.             // testcase: remove title from band; add back; make sure the text
  1931.             // shows up (used to just leave old band contents there)
  1932.             SetRect(&rc, prbb->x, prbb->y, prbb->x + prbb->cx, prbb->y + prbb->cy);
  1933.             RBInvalidateRect(prb, &rc);
  1934.         }
  1935.     }
  1936.     
  1937.     return(TRUE);
  1938. }
  1939. // ----------------------------------------------------------------------------
  1940. //
  1941. // RBReallocBands
  1942. //
  1943. // reallocates the array of bands pointed to by prb->rbbList to the given
  1944. // number of bands
  1945. //
  1946. // ----------------------------------------------------------------------------
  1947. BOOL  RBReallocBands(PRB prb, UINT cBands)
  1948. {
  1949.     PRBB rbbList;
  1950.     if (!(rbbList = (PRBB) CCLocalReAlloc(prb->rbbList, sizeof(RBB) * cBands)) && cBands)
  1951.         return(FALSE);
  1952.     prb->rbbList = rbbList;
  1953.     return(TRUE);
  1954. }
  1955. //
  1956. // NOTES
  1957. //  for now caller does this in two calls (query, set).  eventually we
  1958. //  should be able to have it do everything up front.
  1959. RBRecalcFirst(int nCmd, PRB prb, PRBB prbbDelHide)
  1960. {
  1961.     switch (nCmd) {
  1962.     case RBC_QUERY:
  1963.     {
  1964.         BOOL fRecalcFirst;
  1965.         // if we're nuking the 1st visible guy,
  1966.         // and there are visible guys after us,
  1967.         // then we need to recompute stuff
  1968.         //
  1969.         // for a testcase, start w/:
  1970.         //  row1: 'standard buttons' + 'brand'
  1971.         //  row2: 'address' + 'links'
  1972.         // now hide 'standard buttons', you should end up w/:
  1973.         //  row1: 'address' + 'links' + 'brand'
  1974.         // if there's a bug, you'll end up w/ (since the break isn't recomputed):
  1975.         //  row1: 'brand'
  1976.         //  row2: 'address' + 'links'
  1977.         // fRecalcFirst = (!uBand && prb->cBands);
  1978.         // if brbbDelHide is the first non-hidden band, and there are other non-hidden bands after it, fRecalcFirst = TRUE;
  1979.         fRecalcFirst = (RBEnumBand(prb, 0, RBBS_HIDDEN) == prbbDelHide) &&
  1980.                        (RBGetNextVisible(prb, prbbDelHide) <= RB_GETLASTBAND(prb));