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

Windows Kernel

Development Platform:

Visual C++

  1.         return fRecalcFirst;
  2.     }
  3.     case RBC_SET: // set
  4.     {
  5.         PRBB prbb1, prbb2;
  6.         prbb1 = RBEnumBand(prb, 0, RBBS_HIDDEN);
  7.         if ((prbb1->fStyle & RBBS_FIXEDSIZE)
  8.           && (prbb2 = RBEnumBand(prb, 1, RBBS_HIDDEN)) <= RB_GETLASTBAND(prb)) {
  9.             // get rid of line break on NEW first item
  10.             prbb2->fStyle &= ~RBBS_BREAK;
  11.         }
  12.         if (prb->ci.style & RBS_FIXEDORDER) {
  13.             // BUGBUG not sure what this does...
  14.             // this is because the min width is now based on it's movability --
  15.             // and since we are deleting (or hiding) the first item,
  16.             // the new first item becomes immovable
  17.             RBBCalcMinWidth(prb, prbb1);
  18.         }
  19.         return TRUE;
  20.     }
  21.     
  22.     default:
  23.         ASSERT(0);
  24.     }
  25.     return FALSE;
  26. }
  27. // ----------------------------------------------------------------------------
  28. //
  29. // RBShowBand
  30. //
  31. // updates show/hide state for the indicated band in the rebar's band array
  32. // (rbbList).
  33. //
  34. // ----------------------------------------------------------------------------
  35. BOOL  RBShowBand(PRB prb, UINT uBand, BOOL fShow)
  36. {
  37.     PRBB prbb;
  38.     BOOL fRecalcFirst;
  39.     if (!prb || (!RB_ISVALIDINDEX(prb, uBand)))
  40.         return(FALSE);
  41.     prbb = RBGETBAND(prb, uBand);
  42.     // if we're nuking the 1st visible guy,
  43.     // then we need to recompute stuff
  44.     fRecalcFirst = RBRecalcFirst(RBC_QUERY, prb, prbb);
  45.     if (fShow)
  46.     {
  47.         prbb->fStyle &= ~RBBS_HIDDEN;
  48.         if (!RBBCalcTextExtent(prb, prbb, NULL))
  49.             RBBCalcMinWidth(prb, prbb);
  50.         if (prbb->hwndChild)
  51.             ShowWindow(prbb->hwndChild, SW_SHOW);
  52.     }
  53.     else
  54.     {
  55.         prbb->fStyle |= RBBS_HIDDEN;
  56.         if (prbb->hwndChild)
  57.             ShowWindow(prbb->hwndChild, SW_HIDE);        
  58.     }
  59.     if (fRecalcFirst)
  60.         RBRecalcFirst(RBC_SET, prb, NULL);
  61.     RBInvalidateRect(prb, NULL);
  62.     RBResize(prb, FALSE);
  63.     RBAutoSize(prb);
  64.     return(TRUE);
  65. }
  66. // ----------------------------------------------------------------------------
  67. //
  68. // RBDeleteBand
  69. //
  70. // deletes the indicated band from the rebar's band array (rbbList) and
  71. // decrements the rebar's band count (cBands)
  72. //
  73. // ----------------------------------------------------------------------------
  74. BOOL  RBDeleteBand(PRB prb, UINT uBand)
  75. {
  76.     PRBB prbb;
  77.     PRBB prbbStop;
  78.     BOOL fRecalcFirst;
  79.     NMREBAR nm = {0};
  80.     ASSERT(prb);
  81.     // we need to clean up
  82.     //
  83.     // a) captured band and
  84.     // b) hottracked band
  85.     //
  86.     // before we delete this band
  87.     if (prb->iCapture != -1) {
  88.         RBSendNotify(prb, prb->iCapture, RBN_ENDDRAG);
  89.         RBOnBeginDrag(prb, (UINT)-1);
  90.     }
  91.     if (!RB_ISVALIDINDEX(prb, uBand))
  92.         return FALSE;
  93.     prbb = RBGETBAND(prb, uBand);
  94.     // Notify the client of the delete
  95.     RBSendNotify(prb, uBand, RBN_DELETINGBAND);
  96.     nm.dwMask = RBNM_ID;
  97.     nm.wID = RBGETBAND(prb, uBand)->wID;        // Save this
  98.     Str_Set(&prbb->lpText, NULL);
  99.     // don't destroy the hbmBack 'cause it's given to us by app
  100.     // if we're nuking the 1st visible guy,
  101.     // then we need to recompute stuff
  102.     // if this is the first visible guy and there are other visible bands after it, fRecalcFirst = TRUE
  103.     fRecalcFirst = RBRecalcFirst(RBC_QUERY, prb, prbb);
  104.     if (IsWindow(prbb->hwndChild))
  105.         ShowWindow(prbb->hwndChild, SW_HIDE);    
  106.     
  107.     // prbbStop gets the address of the last band
  108.     prbbStop = RB_GETLASTBAND(prb);
  109.     for ( ; prbb < prbbStop; prbb++)
  110.         *prbb = *(prbb + 1);
  111.     prb->cBands--;
  112.     if (prb->uResizeNext >= uBand && prb->uResizeNext > 0) {
  113.         // (defer RBBS_HIDDEN stuff to use of uResizeNext)
  114.         prb->uResizeNext--;
  115.     }
  116.     // Notify the client of the delete
  117.     CCSendNotify(&prb->ci, RBN_DELETEDBAND, &nm.hdr);
  118.     if (fRecalcFirst)
  119.         RBRecalcFirst(RBC_SET, prb, NULL);
  120.     RBReallocBands(prb, prb->cBands);
  121.     RBInvalidateRect(prb, NULL);
  122.     RBResize(prb, FALSE);
  123.     RBAutoSize(prb);
  124.     return(TRUE);
  125. }
  126. // ----------------------------------------------------------------------------
  127. //
  128. // RBInsertBand
  129. //
  130. // inserts a new band at the given position in the rebar's band array (rbbList),
  131. // increments the rebar's band count (cBands), and sets the band's structure
  132. // based on the given REBARBANDINFO structure.
  133. //
  134. // ----------------------------------------------------------------------------
  135. BOOL  RBInsertBand(PRB prb, UINT uBand, LPREBARBANDINFO lprbbi)
  136. {
  137.     PRBB prbb;
  138.     REBARBANDINFO rbbi = {0};
  139.     if (!prb || !RBValidateBandInfo(&lprbbi, &rbbi))
  140.         return(FALSE);
  141.     
  142.     if (uBand == -1)
  143.         uBand = prb->cBands;
  144.     else if (uBand > prb->cBands)
  145.         return(FALSE);
  146.     if (!RBReallocBands(prb, prb->cBands + 1))
  147.         return(FALSE);
  148.     ++prb->cBands;
  149.     MoveMemory(RBGETBAND(prb, uBand + 1), RBGETBAND(prb, uBand), (prb->cBands-1-uBand) * sizeof(prb->rbbList[0]));
  150.     prbb = RBGETBAND(prb, uBand);
  151.     // movememory does not zero init for us...
  152.     ZeroMemory(prbb, SIZEOF(RBB));
  153.     // Init text color
  154.     if (prb->clrText == CLR_NONE)
  155.     {
  156.         // Default to system text color
  157.         prbb->clrFore = CLR_DEFAULT;
  158.     }
  159.     else
  160.     {
  161.         // Default to rebar's custom text color
  162.         prbb->clrFore = CLR_NONE;
  163.     }
  164.     // Init background color
  165.     if (prb->clrBk == CLR_NONE)
  166.     {
  167.         // Default to system background color
  168.         prbb->clrBack = CLR_DEFAULT;
  169.     }
  170.     else
  171.     {
  172.         // Default to rebar's custom background color
  173.         prbb->clrBack = CLR_NONE;
  174.     }
  175.     
  176.     prbb->iImage = -1;
  177.     prbb->cyMaxChild = MAXINT;
  178.     prbb->wChevState = DCHF_INACTIVE;
  179.     
  180.     ASSERT(prbb->fStyle == 0);
  181.     ASSERT(prbb->lpText == NULL);
  182.     ASSERT(prbb->cxText == 0);
  183.     ASSERT(prbb->hwndChild == NULL);
  184.     ASSERT(prbb->cxMinChild == 0);
  185.     ASSERT(prbb->cyMinChild == 0);
  186.     ASSERT(prbb->hbmBack == 0);
  187.     ASSERT(prbb->x == 0);
  188.     ASSERT(prbb->y == 0);
  189.     ASSERT(prbb->cx == 0);
  190.     ASSERT(prbb->cy == 0);
  191.     
  192.     if (!RBSetBandInfo(prb, uBand, lprbbi, FALSE))
  193.     {
  194.         RBDeleteBand(prb, uBand);
  195.         return(FALSE);
  196.     }
  197.     
  198.     if (!(prbb->fStyle & RBBS_HIDDEN)) {
  199.         PRBB prbbFirst = RBEnumBand(prb, 0, RBBS_HIDDEN);
  200.         
  201.         if (!prbb->cxMin)
  202.             RBBCalcMinWidth(prb, prbb);
  203.         if (prbbFirst != prbb) {
  204.             int cxMin = prbbFirst->cxMin;
  205.             RBBCalcMinWidth(prb, prbbFirst);
  206.         }
  207.         RBResize(prb, FALSE);
  208.     }
  209.     RBSizeBandToRowHeight(prb, uBand, (UINT)-1);
  210.     if (RBCountBands(prb, RBBS_HIDDEN) == 1) {
  211.         // typcially, when you insert a band, we put it in a row with another band.
  212.         // thus the total bounding rect doesn't change.  however, on the addition of the first band,
  213.         // the bound rect does change, so we need to autosize as necessary.
  214.         RBAutoSize(prb);
  215.     }
  216.     return(TRUE);
  217. }
  218. #pragma code_seg(CODESEG_INIT)
  219. LRESULT CALLBACK ReBarWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  220. BOOL InitReBarClass(HINSTANCE hInstance)
  221. {
  222.     WNDCLASS wc;
  223.     if (!GetClassInfo(hInstance, c_szReBarClass, &wc))
  224.     {
  225. #ifndef WIN32
  226.         extern LRESULT CALLBACK _ReBarWndProc(HWND, UINT, WPARAM, LPARAM);
  227.         wc.lpfnWndProc  = _ReBarWndProc;
  228. #else
  229.         wc.lpfnWndProc  = (WNDPROC) ReBarWndProc;
  230. #endif
  231.         wc.lpszClassName= c_szReBarClass;
  232.         wc.style        = CS_GLOBALCLASS | CS_DBLCLKS;
  233.         wc.cbClsExtra   = 0;
  234.         wc.cbWndExtra   = sizeof(PRB);
  235.         wc.hInstance    = hInstance;   // use DLL instance if in DLL
  236.         wc.hIcon        = NULL;
  237.         wc.hCursor      = NULL;
  238.         wc.hbrBackground= (HBRUSH)(COLOR_BTNFACE + 1);
  239.         wc.lpszMenuName = NULL;
  240.         if (!RegisterClass(&wc))
  241.             return(FALSE);
  242.     }
  243.     return(TRUE);
  244. }
  245. #pragma code_seg()
  246. // get the first band in the same row as rbbRow
  247. // n.b. we may return an RBBS_HIDDEN band!
  248. PRBB RBGetFirstInRow(PRB prb, PRBB prbbRow)
  249. {
  250.     // n.b. we don't pay attention to hidden here, that's up to caller.
  251.     // in fact we *can't*, since there might be no non-hidden guys left
  252.     // (e.g. when RBDestroy is deleting all the bands), in which case
  253.     // we'd loop forever.
  254.     while (prbbRow > RBGETBAND(prb, 0) && !RBISBANDSTARTOFROW(prbbRow)) {
  255.         RBCheckRangePtr(prb, prbbRow);
  256.         prbbRow--;
  257.     }
  258.     
  259.     return prbbRow;
  260. }
  261. // get the last band in the same row as rbbRow.
  262. // fStopAtFixed says whether to continue over fixed bands or 
  263. // stop at them
  264. // n.b. we may return an RBBS_HIDDEN band!
  265. PRBB RBGetLastInRow(PRB prb, PRBB prbbRow, BOOL fStopAtFixed)
  266. {
  267.     do {
  268.         prbbRow++;
  269.     } while (prbbRow <= RB_GETLASTBAND(prb) && !RBISBANDSTARTOFROW(prbbRow) && 
  270.         (!fStopAtFixed || (prbbRow->fStyle & (RBBS_FIXEDSIZE|RBBS_HIDDEN)) == RBBS_FIXEDSIZE));
  271.     // loop steps to the start of the NEXT line
  272.     prbbRow--;
  273.     
  274.     return prbbRow;
  275. }
  276. #ifdef DEBUG
  277. BOOL RBCheckRangePtr(PRB prb, PRBB prbb)
  278. {
  279.     if (prbb < RBGETBAND(prb, 0)) {
  280.         ASSERT(0);
  281.         return FALSE;
  282.     }
  283.     if (RB_GETLASTBAND(prb) + 1 < prbb) {
  284.         // +1 to allow for "p = first; p < last+1; p++" kinds of loops
  285.         ASSERT(0);
  286.         return FALSE;
  287.     }
  288.     return TRUE;
  289. }
  290. BOOL RBCheckRangeInd(PRB prb, INT_PTR i)
  291. {
  292.     if (i < 0) {
  293.         ASSERT(0);
  294.         return FALSE;
  295.     }
  296.     if ((int) prb->cBands < i) {
  297.         // +1 to allow for "p = first; p < last+1; p++" kinds of loops
  298.         ASSERT(0);
  299.         return FALSE;
  300.     }
  301.     return TRUE;
  302. }
  303. #endif
  304. //***   RBGetPrev, RBGetNext -- get prev (next) band, skipping guys
  305. // of style uStyleSkip (e.g. RBBS_HIDDEN)
  306. PRBB RBGetPrev(PRB prb, PRBB prbb, UINT uStyleSkip)
  307. {
  308.     while (--prbb >= RBGETBAND(prb, 0)) {
  309.         if (prbb->fStyle & uStyleSkip)
  310.             continue;
  311.         break;
  312.     }
  313.     return prbb;
  314. }
  315. // when called with prbb=lastband, returns prbb++
  316. // which is one past the end...
  317. PRBB RBGetNext(PRB prb, PRBB prbb, UINT uStyleSkip)
  318. {
  319.     while (++prbb <= RB_GETLASTBAND(prb)) {
  320.         if (prbb->fStyle & uStyleSkip)
  321.             continue;
  322.         break;
  323.     }
  324.     return prbb;
  325. }
  326. // this returns NULL when it hits the end
  327. PRBB RBBNextVisible(PRB prb, PRBB prbb)
  328. {
  329.     prbb = RBGetNextVisible(prb, prbb);
  330.     if (prbb > RB_GETLASTBAND(prb))
  331.         return NULL;
  332.     
  333.     return prbb;
  334. }
  335. // this returns null when it hits the end
  336. PRBB RBBPrevVisible(PRB prb, PRBB prbb)
  337. {
  338.     prbb = RBGetPrevVisible(prb, prbb);
  339.     if (prbb < prb->rbbList)
  340.         return NULL;
  341.     
  342.     return prbb;
  343. }
  344. //***   RBCountBands -- get count of bands, skipping guys
  345. // of style uStyleSkip (e.g. RBBS_HIDDEN)
  346. int RBCountBands(PRB prb, UINT uStyleSkip)
  347. {
  348.     int i;
  349.     PRBB prbb;
  350.     if (prb->cBands == 0)
  351.         return 0;
  352.     i = 0;
  353.     for (prbb = RBGETBAND(prb, 0); prbb <= RB_GETLASTBAND(prb); prbb++) {
  354.         if (prbb->fStyle & uStyleSkip)
  355.             continue;
  356.         i++;
  357.     }
  358.     return i;
  359. }
  360. //***   RBEnumBand -- get Nth band, skipping guys
  361. // of style uStyleSkip (e.g. RBBS_HIDDEN)
  362. // 'skipping' means don't include in count
  363. PRBB RBEnumBand(PRB prb, int i, UINT uStyleSkip)
  364. {
  365.     PRBB prbb;
  366.     for (prbb = RBGETBAND(prb, 0); prbb <= RB_GETLASTBAND(prb); prbb++) {
  367.         if (prbb->fStyle & uStyleSkip)
  368.             continue;
  369.         if (i-- == 0)
  370.             break;
  371.     }
  372.     // if we found it, this is the band;
  373.     // if we ran out of bands, this is 1 past the end
  374.     return prbb;
  375. }
  376. // returns the minimum x position prbb can be
  377. int RBMinX(PRB prb, PRBB prbb)
  378. {
  379.     int xLimit = 0;
  380.     ASSERT(!(prbb->fStyle & RBBS_HIDDEN));  // o.w. might loop forever
  381.     while (!RBISBANDSTARTOFROW(prbb))
  382.     {
  383.         prbb--;
  384.         if (!(prbb->fStyle & RBBS_HIDDEN))
  385.             xLimit += _RBBandWidth(prb, prbb->cxMin);
  386.     }
  387.     
  388.     return xLimit;
  389. }
  390. int RBMaxX(PRB prb, PRBB prbb)
  391. {
  392.     PRBB    prbbLast = prb->rbbList + prb->cBands;
  393.     int xLimit = 0;
  394.     PRBB prbbWalk;
  395.     for (prbbWalk = prbb; prbbWalk < prbbLast; prbbWalk++) {
  396.         if (prbbWalk->fStyle & RBBS_HIDDEN)
  397.             continue;
  398.         if (RBISBANDSTARTOFROW(prbbWalk))
  399.             break;
  400.         if (prbbWalk != prbb)
  401.             xLimit += _RBBandWidth(prb, prbbWalk->cxMin);
  402.         else 
  403.             xLimit += prbbWalk->cxMin;
  404.     }
  405.     prbbWalk = RBGetPrevVisible(prb, prbbWalk);   // prbbWalk--;
  406.     xLimit = prbbWalk->x + prbbWalk->cx - xLimit;
  407.     return xLimit;
  408. }
  409. PRBB RBGetPrevVisible(PRB prb, PRBB prbb)
  410. {
  411.     return RBGetPrev(prb, prbb, RBBS_HIDDEN);
  412. }
  413. PRBB RBGetNextVisible(PRB prb, PRBB prbb)
  414. {
  415.     return RBGetNext(prb, prbb, RBBS_HIDDEN);
  416. }
  417. BOOL RBMinimizeBand(PRB prb, UINT uBand, BOOL fAnim)
  418. {
  419.     PRBB prbb;
  420.     if (!RB_ISVALIDINDEX(prb, uBand))
  421.         return FALSE;
  422.     prbb=RBGETBAND(prb,uBand);
  423.     if (prbb->fStyle & RBBS_FIXEDSIZE)
  424.         return FALSE;
  425.     
  426.     ASSERT(!(prbb->fStyle & RBBS_HIDDEN));
  427.     if (RBISBANDSTARTOFROW(prbb)) {
  428.         // if it's the start of a row, the way to minimize it is to maximize the next guy
  429.         // if it's on the same row
  430.         prbb = RBGetNextVisible(prb, prbb);
  431.         if (prbb > RB_GETLASTBAND(prb) || RBISBANDSTARTOFROW(prbb)) 
  432.             return FALSE;
  433.         
  434.         return RBMaximizeBand(prb, RBBANDTOINDEX(prb,prbb), FALSE, fAnim);
  435.     }
  436.     if (fAnim)
  437.         return RBSetBandPosAnim(prb, prbb, prbb->x + (prbb->cx - prbb->cxMin));
  438.     else
  439.         return RBSetBandPos(prb, prbb, prbb->x + (prbb->cx - prbb->cxMin));
  440. }
  441. // fIdeal - FALSE == full maximization...  
  442. //          TRUE == go to cxIdeal
  443. // fAnim - TRUE means we were called due to UI action (via RBToggleBand), so animate
  444. BOOL RBMaximizeBand(PRB prb, UINT uBand, BOOL fIdeal, BOOL fAnim)
  445. {
  446.     int x, dx;
  447.     BOOL fChanged = FALSE;
  448.     PRBB prbbMaximize;
  449.     if (!RB_ISVALIDINDEX(prb, uBand))
  450.         return FALSE;
  451.     prbbMaximize = RBGETBAND(prb,uBand);
  452.     if (prbbMaximize->fStyle & RBBS_FIXEDSIZE)
  453.         return FALSE;
  454.     dx = prbbMaximize->cxIdeal + RBBHEADERWIDTH(prbbMaximize) - prbbMaximize->cx;
  455.     
  456.     if (fIdeal && dx > 0) 
  457.     {
  458.         PRBB prbb;
  459.         
  460.         // first move the next guy over if possible.
  461.         prbb = RBBNextVisible(prb, prbbMaximize);
  462.         if (prbb && (!RBISBANDSTARTOFROW(prbb)))
  463.         {
  464.             int dxRbb;
  465.             x = RBMaxX(prb, prbb);
  466.             // dxRbb is the maximum that prbb can move
  467.             dxRbb = x - prbb->x;
  468.             if (dxRbb > dx) {
  469.                 // if that's more than enough space, then limit dx
  470.                 dxRbb = dx;
  471.             }
  472.             x = prbb->x + dxRbb;
  473.             fChanged |= (fAnim)?RBSetBandPosAnim(prb, prbb, x):RBSetBandPos(prb,prbb,x);
  474.             dx -= dxRbb;
  475.         }
  476.         if (dx) {
  477.             int dxRbb;
  478.             // the one on the right didn't move enough.
  479.             // now move us back
  480.             x = RBMinX(prb, prbbMaximize);
  481.             dxRbb = prbbMaximize->x - x;
  482.             if (dxRbb > dx) {
  483.                 x = prbbMaximize->x - dx;
  484.             }
  485.             fChanged |= (fAnim)?RBSetBandPosAnim(prb, prbbMaximize, x):RBSetBandPos(prb, prbbMaximize, x);
  486.         }
  487.         
  488.     } else {    
  489.         x = RBMinX(prb, prbbMaximize);
  490.         fChanged |= (fAnim)?RBSetBandPosAnim(prb, prbbMaximize, x):RBSetBandPos(prb, prbbMaximize, x);
  491.         prbbMaximize = RBBNextVisible(prb, prbbMaximize);
  492.         if (prbbMaximize && !RBISBANDSTARTOFROW(prbbMaximize)) {
  493.             x = RBMaxX(prb, prbbMaximize);
  494.             fChanged |= (fAnim)?RBSetBandPosAnim(prb, prbbMaximize, x):RBSetBandPos(prb, prbbMaximize, x);
  495.         }
  496.     }
  497.             
  498.     return fChanged;
  499. }
  500. // ----------------------------------------------------------------------------
  501. //
  502. // RBToggleBand
  503. //
  504. // switches a band between it's maximized and minimized state, based on where
  505. // the user clicked
  506. //
  507. // ----------------------------------------------------------------------------
  508. void  RBToggleBand(PRB prb, BOOL fAnim)
  509. {
  510.     BOOL fDidSomething = FALSE;
  511.     // try to maximize this band.  if failed (meaning already maximize)
  512.     // then minimize
  513.     if (CCSendNotify(&prb->ci, RBN_MINMAX, NULL))
  514.         return;            
  515.     fDidSomething = RBMaximizeBand(prb, prb->iCapture, TRUE,fAnim);
  516.     if (!fDidSomething)
  517.         fDidSomething = RBMinimizeBand(prb, prb->iCapture,fAnim);
  518.     if (fDidSomething)
  519.         CCPlaySound(TEXT("ShowBand"));
  520. }
  521. // ----------------------------------------------------------------------------
  522. //
  523. // RBSetCursor
  524. //
  525. // sets the cursor to either the move cursor or the arrow cursor, depending
  526. // on whether or not the cursor is on a band's caption
  527. //
  528. // ----------------------------------------------------------------------------
  529. void  RBSetCursor(PRB prb, int x, int y, BOOL fMouseDown)
  530. {
  531.     int             iBand;
  532.     RBHITTESTINFO   rbht;
  533.     rbht.pt.x = x;
  534.     rbht.pt.y = y;
  535.     iBand = RBHitTest(prb, &rbht);
  536.     if (rbht.flags == RBHT_GRABBER)
  537.     {
  538.         if (fMouseDown)
  539.             SetCursor(LoadCursor(HINST_THISDLL, (prb->ci.style & CCS_VERT) ? MAKEINTRESOURCE(IDC_DIVOPENV) : MAKEINTRESOURCE(IDC_DIVOPEN) ));
  540.         else
  541.             SetCursor(LoadCursor(NULL, (prb->ci.style & CCS_VERT) ? IDC_SIZENS : IDC_SIZEWE));
  542.         return;
  543.     }
  544.     if ((fMouseDown) && ((rbht.flags == RBHT_GRABBER) || (rbht.flags == RBHT_CAPTION) && RBShouldDrawGripper(prb, RBGETBAND(prb, iBand))))
  545.     {
  546.         // No longer IE3 compatible, per RichSt
  547.         SetCursor(LoadCursor(NULL, IDC_SIZEALL));
  548.         return;
  549.     }
  550.     SetCursor(LoadCursor(NULL, IDC_ARROW));
  551. }
  552. // adjust's a band's (prbb) starting location to the given location
  553. BOOL RBSetBandPos(PRB prb, PRBB prbb, int xLeft)
  554. {
  555.     RECT    rc;
  556.     PRBB    prbbPrev;
  557.     int     xRight;
  558.     BOOL    fBandBorders = (prb->ci.style & RBS_BANDBORDERS);
  559.     BOOL    fRight;
  560.     ASSERT(!(prbb->fStyle & RBBS_HIDDEN));
  561.     ASSERT((xLeft >= 0)); // We've got problems if someone is trying to set us negative
  562.     if (prbb->x == xLeft)
  563.         return(FALSE);
  564.     prbbPrev = RBGetPrevVisible(prb, prbb);
  565.     // band has moved within valid range -- adjust band sizes and redraw
  566.     // window
  567.     fRight = (prbb->x < xLeft);
  568.     SetRect(&rc, prbb->x, prbb->y, prbb->x + prbb->cxMin, prbb->y + prbb->cy);
  569.     xRight = prbb->x + prbb->cx;
  570.     prbb->x = xLeft;
  571.     prbb->cx = xRight - xLeft;
  572.     prbb->cxRequest = prbb->cx;
  573.     if (fRight)
  574.     {
  575.         //moving right
  576.         prbbPrev->cx = prbb->x - prbbPrev->x;
  577.         if (fBandBorders)
  578.         {
  579.             prbbPrev->cx -= g_cxEdge;
  580.             rc.left -= g_cxEdge;
  581.         }
  582.         prbbPrev->cxRequest = prbbPrev->cx;
  583.         //check for compacting of following bands
  584.         while (prbb->cx < prbb->cxMin)
  585.         {
  586.             prbb->cx = prbb->cxMin;
  587.             prbb->cxRequest = prbb->cx;
  588.             xLeft += RBBANDWIDTH(prb, prbb);
  589.             prbb = RBGetNextVisible(prb, prbb);   // prbb++;
  590.             xRight = prbb->x + prbb->cx;
  591.             prbb->x = xLeft;
  592.             prbb->cx = xRight - xLeft;
  593.             prbb->cxRequest = prbb->cx;
  594.         }
  595.         rc.right = xLeft + prbb->cxMin;
  596.     }
  597.     else
  598.     {
  599.         //moving left
  600.         //check for compacting of preceding bands
  601. CompactPrevious:
  602.         if (fBandBorders)
  603.             xLeft -= g_cxEdge;
  604.         prbbPrev->cx = xLeft - prbbPrev->x;
  605.         prbbPrev->cxRequest = prbbPrev->cx;
  606.         if (prbbPrev->cx < prbbPrev->cxMin)
  607.         {
  608.             prbbPrev->x = xLeft - prbbPrev->cxMin;
  609.             prbbPrev->cx = prbbPrev->cxMin;
  610.             prbbPrev->cxRequest = prbbPrev->cx;
  611.             xLeft = prbbPrev->x;
  612.             prbbPrev = RBGetPrevVisible(prb, prbbPrev);   // prbbPrev--
  613.             goto CompactPrevious;
  614.         }
  615.         rc.left = xLeft;
  616.     }
  617.     if (fBandBorders)
  618.         rc.bottom += g_cyEdge / 2;
  619.     RBResizeChildren(prb);
  620.     if (RBInvalidateRect(prb, &rc))
  621.         UpdateWindow(prb->ci.hwnd);
  622.     return(TRUE);
  623. }
  624. BOOL RBSetBandPosAnim(PRB prb, PRBB prbb, int xLeft)
  625. {
  626.     int ctr=0,dx, xCur = prbb->x;
  627.     DWORD dwStartTime;
  628.     if (xCur == xLeft)
  629.         return FALSE;
  630.     dwStartTime=GetTickCount();
  631.     dx = (xLeft - xCur)/RB_ANIMSTEPS;
  632.     if (dx != 0)
  633.     {
  634.         if (xCur < xLeft) {
  635.             // move right
  636.             for (; xCur < (xLeft-dx); ctr++,xCur += dx) {
  637.                 RBSetBandPos(prb, prbb, xCur);
  638.                 // If something caused us to take more than 10 times the time we
  639.                 // should be, break out, and let the final RBSetBandPos finish
  640.                 if (GetTickCount() > (dwStartTime + 10*RB_ANIMSTEPS*RB_ANIMSTEPTIME))
  641.                     break;
  642.                 Sleep(RB_ANIMSTEPTIME);
  643.                 // Start slowing us down 80% of the way through
  644.                 // Cut speed by 2/3 each time, but never move less than 4 pixels
  645.                 if ((ctr >= 4*RB_ANIMSTEPS/5) && (dx >= 4))
  646.                     dx = 2*dx/3; 
  647.             }
  648.         }
  649.         else {
  650.             // move left
  651.             for (; xCur > (xLeft-dx); ctr++, xCur += dx) {
  652.                 RBSetBandPos(prb, prbb, xCur);
  653.                 if (GetTickCount() > (dwStartTime + 10*RB_ANIMSTEPS*RB_ANIMSTEPTIME))
  654.                     break;
  655.                 Sleep(RB_ANIMSTEPTIME);
  656.                 if ((ctr >= 4*RB_ANIMSTEPS/5) && (dx <= -4))
  657.                     dx = 2*dx/3;
  658.             }
  659.         }
  660.     }
  661.     RBSetBandPos(prb, prbb, xLeft);
  662.     return TRUE;
  663. }
  664. // ----------------------------------------------------------------------------
  665. //
  666. // RBDragSize
  667. //
  668. // adjust the captured band's starting location to the given location and
  669. // redraw
  670. //
  671. // ----------------------------------------------------------------------------
  672. BOOL RBDragSize(PRB prb, int xLeft)
  673. {
  674.     return RBSetBandPos(prb, RBGETBAND(prb, prb->iCapture), xLeft);
  675. }
  676. void RBOnBeginDrag(PRB prb, UINT uBand)
  677. {
  678.     prb->iCapture = (int)uBand;
  679.     prb->ptLastDragPos.x = -1;
  680.     prb->ptLastDragPos.y = -1;
  681.     if (prb->iCapture == -1) {
  682.        // aborting drag
  683.         prb->fParentDrag = FALSE;
  684.         prb->fFullOnDrag = FALSE;
  685.         // we could have unwrapped rows, in which case, we need to grow bands (but not wrap)
  686.         // to fill the empty space.
  687.         if (prb->ci.style & RBS_AUTOSIZE) {
  688.             RBSizeBandsToRect(prb, NULL);
  689.             RBSizeBandsToRowHeight(prb);
  690.         }
  691.         
  692.     } else {
  693.         prb->fParentDrag = TRUE;
  694.         prb->fFullOnDrag = TRUE;
  695.     }
  696. }
  697. int minmax(int x, int min, int max)
  698. {
  699.     x = max(x, min);
  700.     x = min(x, max);
  701.     return x;
  702. }
  703. // pass the break bit along
  704. void RBPassBreak(PRB prb, PRBB prbbSrc, PRBB prbbDest)
  705. {
  706.     if (prbbSrc->fStyle & RBBS_BREAK) {
  707.         prbbSrc->fStyle &= ~RBBS_BREAK;
  708.         if (prbbDest)
  709.             prbbDest->fStyle |= RBBS_BREAK;
  710.     }
  711. }
  712. void RBGetClientRect(PRB prb, LPRECT prc)
  713. {
  714.     GetClientRect(prb->ci.hwnd, prc);
  715.     if (prb->ci.style & CCS_VERT)
  716.         FlipRect(prc);
  717. }
  718. //tells if prbb is the first band and the next band is fixed.
  719. // if this is true then we need to do a recalc if we move prbb
  720. BOOL RBRecalcIfMove(PRB prb, PRBB prbb)
  721. {
  722.     if (RBEnumBand(prb, 0, RBBS_HIDDEN) == prbb) {
  723.         PRBB prbbNext = RBBNextVisible(prb, prbb);
  724.         if (prbbNext && prbbNext->fStyle & RBBS_FIXEDSIZE)
  725.             return TRUE;
  726.     }
  727.     return FALSE;
  728. }
  729. // find out if the prbb at it's min height could fit within the current window
  730. // if all the others shrunk as much as they could
  731. BOOL RBRoomForBandVert(PRB prb, PRBB prbbSkip)
  732. {
  733.     int yExtra = 0;
  734.     int cBands = prb->cBands;
  735.     int iNewRowHeight = prbbSkip->cyMinChild;
  736.     PRBB prbb = RBGETBAND(prb, 0);
  737.     
  738.     if (prb->ci.style & RBS_BANDBORDERS)
  739.         iNewRowHeight += g_cyEdge;
  740.     
  741.     while (prbb) {
  742.         if (RBISBANDVISIBLE(prbb)) {
  743.             if (RBISBANDSTARTOFROW(prbb)) {
  744.                 yExtra += RBGetRowHeightExtra(prb, &prbb, prbbSkip);
  745.                 if (yExtra >= iNewRowHeight)
  746.                     return TRUE;
  747.                 continue;
  748.             }
  749.         }
  750.         prbb = RBBNextVisible(prb, prbb);
  751.     }
  752.     
  753.     return FALSE;
  754. }
  755. // we should make a new row if prbb isn't the start of the row already
  756. // and we're off the end of the control
  757. //
  758. // poweruser hack of holding the control down will make a new row if you hit the border between lines
  759. BOOL RBMakeNewRow(PRB prb, PRBB prbb, int y)
  760. {
  761.     BOOL fRet = FALSE;
  762.     RECT rc;
  763.     // if we're off the top of the control, move this band to the end (or beginning)
  764.     RBGetClientRect(prb, &rc);
  765.     InflateRect(&rc, 0, -g_cyEdge);
  766.     if (!(prb->ci.style & RBS_FIXEDORDER)) {
  767.         int iOutsideLimit = g_cyEdge * 4; // how far do you have to move outside the bounds of the window to force a new row
  768.         
  769.         if (RBRoomForBandVert(prb, prbb)) {
  770.             iOutsideLimit = -g_cyEdge;
  771.         }
  772.         
  773.         if (y < rc.top - iOutsideLimit) { // top of control
  774.             
  775.             PRBB prbbNext = RBEnumBand(prb, 0, RBBS_HIDDEN);
  776.             if (prbbNext == prbb) 
  777.                 prbbNext = RBBNextVisible(prb, prbb);
  778.             fRet |= RBMoveBand(prb, RBBANDTOINDEX(prb, prbb), 0);
  779.             ASSERT(prbbNext <= RB_GETLASTBAND(prb));
  780.             if (prbbNext && !(prbbNext->fStyle & RBBS_BREAK)) {
  781.                 prbbNext->fStyle |= RBBS_BREAK;
  782.                 fRet = TRUE;
  783.             }
  784.         } else if (y >= rc.bottom + iOutsideLimit) { // move to the end
  785.             if (!(prbb->fStyle & RBBS_BREAK)) {
  786.                 prbb->fStyle |= RBBS_BREAK;
  787.                 fRet = TRUE;
  788.             }
  789.             fRet |= RBMoveBand(prb, RBBANDTOINDEX(prb, prbb), prb->cBands-1);
  790.         } else {
  791.             // create a new row in the middle
  792.             if (!RBISBANDSTARTOFROW(prbb) && GetAsyncKeyState(VK_CONTROL) < 0) {
  793.                 // make sure they're on different rows and on the border
  794.                 if (y > prbb->y + prbb->cy && (y < prbb->y + prbb->cy + g_cyEdge)) {
  795.                     PRBB prbbLast = RBGetLastInRow(prb, prbb, FALSE);  // move it right before the first in this row
  796.                     prbb->fStyle |= RBBS_BREAK;
  797.                     RBMoveBand(prb, RBBANDTOINDEX(prb, prbb), RBBANDTOINDEX(prb, prbbLast));
  798.                     fRet = TRUE;
  799.                 }
  800.             }
  801.         }
  802.     } else {
  803.         // fixed guys can't move, they can only make a new row
  804.         if (!RBISBANDSTARTOFROW(prbb)) {
  805.             if (y > prbb->y + prbb->cy) {
  806.                 prbb->fStyle |= RBBS_BREAK;
  807.                 fRet = TRUE;
  808.             }
  809.         }
  810.     }
  811.     
  812.     if (fRet)
  813.         RBResize(prb, FALSE);
  814.     return fRet;
  815. }
  816. // ----------------------------------------------------------------------------
  817. //
  818. // RBDragBand
  819. //
  820. // resizes the currently tracked band based on the user's mouse movement as
  821. // indicated in the given point (x, y)
  822. //
  823. // ----------------------------------------------------------------------------
  824. void RBDragBand(PRB prb, int x, int y)
  825. {
  826.     PRBB prbb = RBGETBAND(prb, prb->iCapture);
  827.     int iHit;
  828.     // Do nothing if the mouse didn't actually move
  829.     // otherwise, multiple WM_MOUSEMOVE messages will be generated by resizing windows
  830.     if (x==prb->ptLastDragPos.x && y==prb->ptLastDragPos.y)
  831.         return;
  832.     else
  833.     {
  834.         prb->ptLastDragPos.x = x;
  835.         prb->ptLastDragPos.y = y;
  836.     }
  837.     if (prb->ci.style & CCS_VERT)
  838.         SWAP(x,y, int);
  839.     if (!prb->fFullOnDrag)
  840.     {
  841.         // don't begin dragging until mouse is moved outside of an edge-thick
  842.         // tolerance border
  843.         if ((y < (prb->ptCapture.y - g_cyEdge)) || (y > (prb->ptCapture.y + g_cyEdge)) ||
  844.             (x < (prb->ptCapture.x - g_cxEdge)) || (x > (prb->ptCapture.x + g_cxEdge))) {
  845.             // did parent abort?
  846.             if (RBSendNotify(prb, prb->iCapture, RBN_BEGINDRAG))
  847.                 return;
  848.             if (!RB_ISVALIDBAND(prb, prbb)) {
  849.                 // somebody responded to RBN_BEGINDRAG by nuking bands; bail
  850.                 return;
  851.             }
  852.             
  853.             prb->fFullOnDrag = TRUE;
  854.         } else
  855.             return;
  856.     }
  857.     
  858.     // bail for right now on fRecalcIfMoved (ie3 did the same thing). nice feature for later
  859.     if (!RBCanBandMove(prb, prbb))
  860.         return;
  861.     
  862.    /* what type of drag operation depends on what we drag hit on.
  863.         if we hit on the band before us, or ourself
  864.           and it's the same row
  865.           and we're not the first band of the row
  866.              then we just to a size move
  867.              
  868.         otherwise if we hit on a band then we do a move 
  869.         
  870.         if we hit outside of any band, we grow to meet the cursor
  871.         
  872.         in all of the above, a band that's hit must be NOT fixed and not hidden
  873.     */
  874.     iHit = _RBHitTest(prb, NULL, x, y);
  875.     
  876.     if (iHit != -1) {
  877.         BOOL fResize = FALSE;
  878.         PRBB prbbPrev = RBBPrevVisible(prb, prbb);
  879.         PRBB prbbHit = RBGETBAND(prb, iHit);
  880.         prbbHit = RBGetPrev(prb, ++prbbHit, RBBS_FIXEDSIZE); // skip over fixed guys
  881.         ASSERT(prbbHit >= prb->rbbList);
  882.         // this should never happen.
  883.         if (prbbHit < prb->rbbList) 
  884.             return;
  885.         
  886.         iHit = RBBANDTOINDEX(prb, prbbHit);
  887.         
  888.         // if we're on the same row ...  and it's us or the previous one
  889.         if (prbbHit->y == prbb->y && (prbbHit == prbb || prbbHit == prbbPrev)) {
  890.             if (x < RB_GRABWIDTH && !(prb->ci.style & RBS_FIXEDORDER)) {
  891.                 // special case dragging to the far left. there's no other way to move to first in row
  892.                 RBPassBreak(prb, prbbHit, prbb);
  893.                 if (RBMoveBand(prb, prb->iCapture, iHit))                
  894.                     fResize = TRUE;
  895.             } else if (!RBISBANDSTARTOFROW(prbb)) {
  896.                 // and we're not the first band of the row
  897.                 // then just size it
  898.                 int xLeft = prb->xStart + (x - prb->ptCapture.x);
  899.                 xLeft = minmax(xLeft, RBMinX(prb, prbb), RBMaxX(prb, prbb));
  900.                 RBDragSize(prb, xLeft);
  901.             }
  902.         } else if (RBMakeNewRow(prb, prbb, y)) {
  903.         } else {            // otherwise do a move if we're not in a fixed order
  904.             if (!(prb->ci.style & RBS_FIXEDORDER)) {
  905.                 if (iHit < RBBANDTOINDEX(prb, prbb)) 
  906.                     iHit++; // +1 because if you hit a band, you're moving to the right of him
  907.                 // if one with a break is moving, the next one inherits the break
  908.                 RBPassBreak(prb, prbb, RBBNextVisible(prb, prbb));
  909.                 RBMoveBand(prb, prb->iCapture, iHit);
  910.             } else {
  911.                 if (iHit < RBBANDTOINDEX(prb, prbb))
  912.                     RBPassBreak(prb, prbb, RBBNextVisible(prb, prbb));
  913.             }
  914.             fResize = TRUE;
  915.         }
  916.         if (fResize)
  917.             RBResize(prb, FALSE);        
  918.         
  919.     } else 
  920.         RBMakeNewRow(prb, prbb, y);    
  921. }
  922. HPALETTE RBSetPalette(PRB prb, HPALETTE hpal)
  923. {
  924.     HPALETTE hpalOld = prb->hpal;
  925.     if (hpal != hpalOld) {
  926.         if (!prb->fUserPalette) {
  927.             if (prb->hpal) {
  928.                 DeleteObject(prb->hpal);
  929.                 prb->hpal = NULL;
  930.             }
  931.         }
  932.         if (hpal) {
  933.             prb->fUserPalette = TRUE;
  934.             prb->hpal = hpal;
  935.         }
  936.         RBInvalidateRect(prb, NULL);
  937.     }
  938.     return hpalOld;
  939. }
  940. // ----------------------------------------------------------------------------
  941. //
  942. // RBDestroy
  943. //
  944. // frees all memory allocated by rebar, including rebar structure
  945. //
  946. // ----------------------------------------------------------------------------
  947. BOOL  RBDestroy(PRB prb)
  948. {
  949.     UINT c = prb->cBands;
  950.     RBSetRedraw(prb, FALSE);
  951.     RBSetRecalc(prb, FALSE);
  952.     
  953.     while (c--)
  954.         RBDeleteBand(prb, c);
  955.     // so that we don't keep trying to autosize
  956.     prb->ci.style &= ~RBS_AUTOSIZE;
  957.     
  958.     ASSERT(!prb->rbbList);
  959.     RBSetPalette(prb, NULL);
  960.     
  961.     if (prb->hFont && prb->fFontCreated) {
  962.         DeleteObject(prb->hFont);
  963.     }
  964.     if ((prb->ci.style & RBS_TOOLTIPS) && IsWindow(prb->hwndToolTips))
  965.     {
  966.         DestroyWindow (prb->hwndToolTips);
  967.         prb->hwndToolTips = NULL;
  968.     }
  969.     // don't destroy the himl 'cause it's given to us by app
  970.     SetWindowPtr(prb->ci.hwnd, 0, 0);
  971.     if (prb->hDragProxy)
  972.         DestroyDragProxy(prb->hDragProxy);
  973.     LocalFree((HLOCAL) prb);
  974.     return(TRUE);
  975. }
  976. // ----------------------------------------------------------------------------
  977. //
  978. // RBInitPaletteHack
  979. //
  980. // this is a hack to use the halftone palette until we have a way of asking
  981. // the client what palette they are using
  982. //
  983. // ----------------------------------------------------------------------------
  984. void  RBInitPaletteHack(PRB prb)
  985. {
  986.     if (!prb->fUserPalette) {
  987.         HDC hdc = CreateCompatibleDC(NULL);
  988.         if (hdc) {
  989.             if (GetDeviceCaps(hdc, BITSPIXEL) <= 8) {
  990.                 if (prb->hpal)
  991.                     DeleteObject(prb->hpal);
  992.                 prb->hpal = CreateHalftonePalette(hdc);  // this is a hack
  993.             }
  994.             DeleteDC(hdc);
  995.         }
  996.     }
  997. }
  998. LRESULT RBIDToIndex(PRB prb, UINT id)
  999. {
  1000.     UINT i;
  1001.     REBARBANDINFO   rbbi;
  1002.     rbbi.cbSize = sizeof(REBARBANDINFO);
  1003.     rbbi.fMask = RBBIM_ID;
  1004.     for (i = 0; i < prb->cBands; i++) {
  1005.         if (RBGetBandInfo(prb, i, &rbbi)) {
  1006.             if (rbbi.wID == (WORD)id)
  1007.                 return i;
  1008.         }
  1009.     }
  1010.     return -1;
  1011. }
  1012. LRESULT RBGetRowHeight(PRB prb, UINT uRow)
  1013. {
  1014.     if (uRow < prb->cBands)
  1015.     {
  1016.         // move back to start of line
  1017.         PRBB prbbFirst = RBGetFirstInRow(prb, RBGETBAND(prb, uRow));
  1018.         PRBB prbbLast = RBGetLastInRow(prb, RBGETBAND(prb, uRow), FALSE);
  1019.         return RBGetLineHeight(prb, RBBANDTOINDEX(prb, prbbFirst), RBBANDTOINDEX(prb, prbbLast));
  1020.     }
  1021.     return (LRESULT)-1;
  1022. }
  1023. // fOneStep == whether to allow  only one cyIntegral or as many as will fit to 
  1024. //     fill dy
  1025. int RBGrowBand(PRB prb, PRBB prbb, int dy, BOOL fOneStep)
  1026. {
  1027.     int iDirection = dy / ABS(dy);
  1028.     int dyBand = 0; // how much the band changes
  1029.     int cyNewHeight;
  1030.     if (prbb->cyIntegral &&
  1031.         prbb->cyIntegral <= (UINT)ABS(dy)) {
  1032.         
  1033.         // get the proposed new size
  1034.         if (fOneStep)
  1035.             dyBand = (prbb->cyIntegral * iDirection);
  1036.         else {
  1037.             int iNumOfIntegrals;
  1038.             
  1039.             // don't let it grow more than the max allowed
  1040.             if (dy >= 0) {
  1041.                 if ((int)(prbb->cyMaxChild - prbb->cyChild) < dy) {
  1042.                     dy = (int)(prbb->cyMaxChild - prbb->cyChild);
  1043.                 }
  1044.             } else {
  1045.                 if ((int)(prbb->cyMinChild - prbb->cyChild) > dy) {
  1046.                     dy = (int)(prbb->cyMinChild - prbb->cyChild);
  1047.                 }
  1048.             }
  1049.             
  1050.             iNumOfIntegrals = (dy / (int) prbb->cyIntegral);
  1051.             dyBand = (prbb->cyIntegral * iNumOfIntegrals);
  1052.                 
  1053.         }
  1054.         
  1055.         cyNewHeight = ((int)prbb->cyChild) + dyBand;
  1056.         // make sure the new size is legal
  1057.         
  1058.         if ((int)prbb->cyMinChild <= cyNewHeight && ((UINT)cyNewHeight) <= prbb->cyMaxChild) {
  1059.             prbb->cyChild = cyNewHeight;
  1060.             RBResize(prb, TRUE);
  1061.         } else
  1062.             dyBand = 0;
  1063.     }
  1064.     return dyBand;
  1065. }
  1066. // returns the delta in size that the rebar is from prc.
  1067. // taking into account vertical mode
  1068. int RBSizeDifference(PRB prb, LPRECT prc)
  1069. {
  1070.     int d;
  1071.     d = (RB_ISVERT(prb) ? RECTWIDTH(*prc) : RECTHEIGHT(*prc))
  1072.         - prb->cy;
  1073.     
  1074.     return d;
  1075. }
  1076. // returns how much this row could shrink
  1077. int RBGetRowHeightExtra(PRB prb, PRBB *pprbb, PRBB prbbSkip)
  1078. {
  1079.     // this is the largest minimum child size for the row. 
  1080.     // even if something is not at it's min size, if it's smaller than this
  1081.     // then it doesn't matter because someone else on that row can't be sized
  1082.     int yLimit = 0;
  1083.     int yExtra = 0;
  1084.     PRBB prbb = *pprbb;
  1085.             
  1086.     while (prbb) {
  1087.         
  1088.         if (prbb != prbbSkip) {
  1089.             int yMin;
  1090.             int yExtraBand = 0;
  1091.             // the min height is the cyChild if it's not variable height
  1092.             yMin = prbb->cyChild;
  1093.             if (prbb->fStyle & RBBS_VARIABLEHEIGHT)
  1094.             {
  1095.                 // if it is variable height, and there's still room to shrink, then cyMinChild is
  1096.                 // the minimum.  
  1097.                 if (prbb->cyChild > prbb->cyMinChild + prbb->cyIntegral) {
  1098.                     yMin = prbb->cyMinChild;
  1099.                     yExtraBand = prbb->cyChild - prbb->cyMinChild;
  1100.                 }
  1101.             }
  1102.             if (yMin == yLimit) {
  1103.                 if (yExtraBand > yExtra)
  1104.                     yExtra = yExtraBand;
  1105.             } else if (yMin > yLimit) {
  1106.                 yExtra = yExtraBand;
  1107.             }
  1108.         }
  1109.         
  1110.         prbb = RBBNextVisible(prb, prbb);
  1111.     }
  1112.     
  1113.     *pprbb = prbb;
  1114.     
  1115.     return yExtra;
  1116. }
  1117. // are allt he bands at the minimum size? 
  1118. BOOL RBBandsAtMinHeight(PRB prb)
  1119. {
  1120.     BOOL fRet = TRUE;
  1121.     int cBands = prb->cBands;
  1122.     
  1123.     PRBB prbb = RBGETBAND(prb, 0);
  1124.     while (prbb) {
  1125.         if (RBISBANDVISIBLE(prbb)) {
  1126.             if (RBISBANDSTARTOFROW(prbb)) {
  1127.                 fRet = RBROWATMINHEIGHT(prb, &prbb);
  1128.                 if (!fRet)
  1129.                     break;
  1130.                 continue;
  1131.             }
  1132.         }
  1133.         prbb = RBBNextVisible(prb, prbb);
  1134.     }
  1135.     
  1136.     return fRet;
  1137. }
  1138. // this is like RBSizeBarToRect except that it resizes theactual bands if they
  1139. // are VARIABLEHEIGHT
  1140. BOOL RBSizeBandsToRect(PRB prb, LPRECT prc)
  1141. {
  1142.     int dy;
  1143.     int iDirection = 0;
  1144.     BOOL fChanged = FALSE;
  1145.     BOOL fChangedThisLoop;
  1146.     UINT cBands;
  1147.     RECT rc;
  1148.     BOOL fRedrawOld;
  1149.     
  1150.     if (prc)
  1151.         rc = *prc;
  1152.     else {
  1153.         GetClientRect(prb->ci.hwnd, &rc);
  1154.     }
  1155.     
  1156.     fRedrawOld = RBSetRedraw(prb, FALSE);
  1157.     
  1158.     // this is the amount we need to grow by
  1159.     do {
  1160.         BOOL fOneStep = TRUE;
  1161.         
  1162.         cBands = prb->cBands;
  1163.         fChangedThisLoop = FALSE;
  1164.         // if there's only one row, we don't need to iterate through all the rows slowly
  1165.         if (RBGetRowCount(prb) == 1)
  1166.             fOneStep = FALSE;
  1167.         
  1168.         dy = RBSizeDifference(prb, &rc);
  1169.         
  1170.         // ensure that we alway size in the same direction.
  1171.         // it's possible to get on the border and flip flop in an infinite
  1172.         // loop.  this happens when we size both horizontally and vertically down
  1173.         // beyond the minimum.  
  1174.         if (iDirection == 0)
  1175.             iDirection = dy;
  1176.         else if (dy * iDirection < 0)
  1177.             break;
  1178.         
  1179.         while (cBands-- && dy) {
  1180.             // when we're resizing the entire rebar,  we want to divvy up
  1181.             // the growth among all the bands (rather than give it all to
  1182.             // a single guy).  uResizeNext goes round-robin thru the bands.
  1183.             PRBB prbb = RBGETBAND(prb, prb->uResizeNext);
  1184.             if (prb->uResizeNext == 0) 
  1185.                 prb->uResizeNext = prb->cBands -1;
  1186.             else
  1187.                 prb->uResizeNext--;
  1188.             
  1189.             if (prbb->fStyle & RBBS_HIDDEN)
  1190.                 continue;
  1191.             if (prbb->fStyle & RBBS_VARIABLEHEIGHT) {
  1192.                 int d;
  1193.                 // if it's a variable height kind of guy, grow/shrink it
  1194.                 d = RBGrowBand(prb, prbb, dy, fOneStep);
  1195.                 dy -= d;
  1196.                 if (d) {
  1197.                     fChanged = TRUE;
  1198.                     fChangedThisLoop = TRUE;
  1199.                     break;
  1200.                 }
  1201.             }
  1202.         }
  1203.         // if we're shrinking 
  1204.         // and we didn't get completely satisfied. we need to overshoot
  1205.         // so that no bands hang off the end and get cut off
  1206.         if (dy < 0 && !fChangedThisLoop && !RBBandsAtMinHeight(prb)) {
  1207.             if (rc.bottom > rc.top) {
  1208.                 rc.bottom -= 1;
  1209.                 fChangedThisLoop = TRUE;
  1210.             }
  1211.         }
  1212.         
  1213.     } while (fChangedThisLoop);
  1214.     RBSetRedraw(prb, fRedrawOld);
  1215.     
  1216.     return fChanged;
  1217. }
  1218. void RBSizeBandToRowHeight(PRB prb, int i, UINT uRowHeight)
  1219. {
  1220.     PRBB prbb = RBGETBAND(prb, i);
  1221.     
  1222.     if (prbb && prbb->fStyle & RBBS_VARIABLEHEIGHT) {
  1223.         if (uRowHeight == (UINT)-1)
  1224.             uRowHeight = (UINT) RBGetRowHeight(prb, i);
  1225.         if (uRowHeight > prbb->cyChild) {
  1226.             RBGrowBand(prb, prbb, (uRowHeight - prbb->cyChild),
  1227.                        FALSE);
  1228.         }
  1229.     }
  1230. }
  1231. // in the process of sizing, one band in a row of several bands might have
  1232. // grow pretty large.  we need to let the other bands have a chance to fill
  1233. // the extra space as well
  1234. void RBSizeBandsToRowHeight(PRB prb)
  1235. {
  1236.     UINT i;
  1237.     UINT iRowHeight = (UINT)-1;
  1238.     
  1239.     for (i = 0; i < prb->cBands; i++) {
  1240.         PRBB prbb = RBGETBAND(prb, i);
  1241.         if (prbb->fStyle & RBBS_HIDDEN)
  1242.             continue;
  1243.         
  1244.         if (RBISBANDSTARTOFROW(prbb))
  1245.             iRowHeight = (UINT) RBGetRowHeight(prb, i);
  1246.         RBSizeBandToRowHeight(prb, i, iRowHeight);
  1247.     }
  1248. }
  1249. // this will add/remove rebar band breaks to get to the requested size.
  1250. // it returns TRUE/FALSE whether something was done or not.
  1251. LRESULT RBSizeBarToRect(PRB prb, LPRECT prc)
  1252. {
  1253.     BOOL fChanged = FALSE;
  1254.     RECT rc;
  1255.     BOOL fRedrawOld = RBSetRedraw(prb, FALSE);
  1256.     if (!prc) {
  1257.         GetClientRect(prb->ci.hwnd, &rc);
  1258.         prc = &rc;
  1259.     }
  1260.     
  1261.     if (prb->cBands) {
  1262.         int c;
  1263.         UINT cBands = prb->cBands;
  1264.         BOOL fChangedThisLoop = TRUE;
  1265.         BOOL fGrowing = TRUE;
  1266.         
  1267.         // if we're shrinking the rebar, we first want to shrink the bands before we start 
  1268.         // removing breaks
  1269.         c = RBSizeDifference(prb, prc);
  1270.         if (c < 0) 
  1271.             fGrowing = FALSE;
  1272.         
  1273.         if (!fGrowing) {
  1274.             fChanged = RBSizeBandsToRect(prb, prc);
  1275.             
  1276.             if (!RBBandsAtMinHeight(prb)) {
  1277.                 // if we're shrinking and all the bands are not down to
  1278.                 // the minimum height, don't try doing any of the breaking stuff
  1279.                 goto Bail;
  1280.             }
  1281.         } else if (RB_ISVERT(prb)) {
  1282.             // if we're in vertical mode, give preference to 
  1283.             // sizing bands before breaking
  1284.             fChanged = RBSizeBandsToRect(prb, prc);
  1285.         }
  1286.         while (fChangedThisLoop && prb->cBands) {
  1287.             int cyRowHalf  = (int) RBGetRowHeight(prb, prb->cBands-1) / 2 ;
  1288.             REBARBANDINFO   rbbi;
  1289.             PRBB prbb;
  1290.             fChangedThisLoop = FALSE;
  1291.             rbbi.cbSize = sizeof(REBARBANDINFO);
  1292.             rbbi.fMask = RBBIM_STYLE;
  1293.             c = RBSizeDifference(prb, prc);
  1294.             if (c < -cyRowHalf) {
  1295.                 // we've shrunk the rebar, try to remove breaks
  1296.                 while (--cBands)
  1297.                 {
  1298.                     prbb = RBGETBAND(prb, cBands);
  1299.                     if (prbb->fStyle & RBBS_HIDDEN)
  1300.                         continue;
  1301.                     if (prbb->fStyle & RBBS_BREAK)
  1302.                     {
  1303.                         fChanged = TRUE;
  1304.                         fChangedThisLoop = TRUE;
  1305.                         rbbi.fStyle = prbb->fStyle & ~RBBS_BREAK;
  1306.                         RBSetBandInfo(prb, cBands, &rbbi, TRUE);
  1307.                         break;
  1308.                     }
  1309.                 }
  1310.             } else if (c > cyRowHalf) {
  1311.                 // we're enlarging the rebar
  1312.                 while (--cBands)
  1313.                 {
  1314.                     prbb = RBGETBAND(prb, cBands);
  1315.                     if (prbb->fStyle & RBBS_HIDDEN)
  1316.                         continue;
  1317.                     if (!(prbb->fStyle & (RBBS_BREAK | RBBS_FIXEDSIZE)))
  1318.                     {
  1319.                         // no break here, add it
  1320.                         fChanged = TRUE;
  1321.                         fChangedThisLoop = TRUE;
  1322.                         rbbi.fStyle = (prbb->fStyle | RBBS_BREAK);
  1323.                         RBSetBandInfo(prb, cBands, &rbbi, TRUE);
  1324.                         break;
  1325.                     }
  1326.                 }
  1327.             }
  1328.         };
  1329.         // if we did as much breaking as we could
  1330.         // and we walked all the way down to the 0th band (we start at the Nth band)
  1331.         // then we try to grow the bands that are VARIABLEHEIGHT
  1332.         // for fGrowing, see comment at top of function
  1333.         // 
  1334.         // wedo the % because cBands == prb->cBands if we didn't go through
  1335.         // any of the breaking loops at all
  1336.         if (!(cBands % prb->cBands) && fGrowing) 
  1337.             fChanged |= RBSizeBandsToRect(prb, prc);
  1338.     }
  1339. Bail:
  1340.     RBSizeBandsToRowHeight(prb);
  1341.     RBSetRedraw(prb, fRedrawOld);
  1342.     
  1343.     return (LRESULT)fChanged;
  1344. }
  1345. void RBAutoSize(PRB prb)
  1346. {
  1347.     NMRBAUTOSIZE nm;
  1348.     
  1349.     // if this is an internal autosize call, but we're not in autosize mode
  1350.     // do nothing
  1351.     
  1352.     if (!(prb->ci.style & RBS_AUTOSIZE))
  1353.         return;
  1354.     
  1355.     
  1356.     GetClientRect(prb->ci.hwnd, &nm.rcTarget);
  1357.     nm.fChanged = (BOOL) RBSizeBarToRect(prb, &nm.rcTarget);
  1358.     GetClientRect(prb->ci.hwnd, &nm.rcActual);
  1359.     CCSendNotify(&prb->ci, RBN_AUTOSIZE, &nm.hdr);
  1360. }
  1361. LRESULT RBGetBandBorders(PRB prb, int wParam, LPRECT prc)
  1362. {
  1363.     BOOL fBandBorders = (prb->ci.style & RBS_BANDBORDERS);
  1364.     PRBB prbb = &prb->rbbList[wParam];
  1365.     prc->left = RBBHEADERWIDTH(prbb);
  1366.     
  1367.     if (fBandBorders) {
  1368.         prc->left += 2*g_cxEdge;
  1369.         prc->right = 0;
  1370.         prc->top = g_cyEdge/2;
  1371.         prc->bottom = g_cyEdge /2;
  1372.     }
  1373.     if (prb->ci.style & CCS_VERT)
  1374.         FlipRect(prc);
  1375.     return 0;
  1376. }
  1377. void RBOnStyleChanged(PRB prb, WPARAM wParam, LPSTYLESTRUCT lpss)
  1378. {
  1379.     if (wParam == GWL_STYLE)
  1380.     {
  1381.         DWORD dwChanged;
  1382.         
  1383.         prb->ci.style = lpss->styleNew;
  1384.         
  1385.         dwChanged = (lpss->styleOld ^ lpss->styleNew);
  1386.         // update to reflect style change
  1387. #ifndef WINNT
  1388.         TraceMsg(TF_REBAR, "rebar window style changed %x", prb->ci.style);
  1389. #endif
  1390.         if (dwChanged & CCS_VERT)
  1391.         {
  1392.             UINT i;
  1393.             for (i = 0; i < prb->cBands; i++) {
  1394.                 if (RBGETBAND(prb, i)->fStyle & RBBS_HIDDEN)
  1395.                     continue;
  1396.                 RBBCalcMinWidth(prb, RBGETBAND(prb, i));
  1397.             }
  1398.             RBResize(prb, TRUE);
  1399.             RBInvalidateRect(prb, NULL);
  1400.         }
  1401.         
  1402.         if (dwChanged & RBS_REGISTERDROP) {
  1403.             
  1404.             if (prb->ci.style & RBS_REGISTERDROP) {
  1405.                 ASSERT(!prb->hDragProxy);
  1406.                 prb->hDragProxy = CreateDragProxy(prb->ci.hwnd, RebarDragCallback, TRUE);
  1407.             } else {
  1408.                 ASSERT(prb->hDragProxy);
  1409.                 DestroyDragProxy(prb->hDragProxy);
  1410.             }
  1411.         }
  1412.     } else if (wParam == GWL_EXSTYLE) {
  1413.         //
  1414.         // If the RTL_MIRROR extended style bit had changed, let's
  1415.         // repaint the control window
  1416.         //
  1417.         if ((prb->ci.dwExStyle&RTL_MIRRORED_WINDOW) !=  (lpss->styleNew&RTL_MIRRORED_WINDOW)) {
  1418.             RBInvalidateRect(prb, NULL);
  1419.         }
  1420.         //
  1421.         // Save the new ex-style bits
  1422.         //
  1423.         prb->ci.dwExStyle = lpss->styleNew;
  1424.     }
  1425. }
  1426. void RBOnMouseMove(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, PRB prb)
  1427. {
  1428.     RelayToToolTips(prb->hwndToolTips, hwnd, uMsg, wParam, lParam);
  1429.     if (prb->iCapture != -1)
  1430.     {
  1431.         // captured band -- mouse is down
  1432.         if (hwnd != GetCapture() && !prb->fParentDrag)
  1433.         {
  1434.             RBSendNotify(prb, prb->iCapture, RBN_ENDDRAG);
  1435.             RBOnBeginDrag(prb, (UINT)-1);
  1436.         }
  1437.         else
  1438.             RBDragBand(prb, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  1439.     }
  1440.     else
  1441.     {
  1442.         // hottracking
  1443.         int iBand;
  1444.         PRBB prbb = NULL;
  1445.         PRBB prbbHotOld = prb->prbbHot;
  1446.         RBHITTESTINFO rbht;
  1447.         rbht.pt.x = GET_X_LPARAM(lParam);
  1448.         rbht.pt.y = GET_Y_LPARAM(lParam);
  1449.         iBand = RBHitTest(prb, &rbht);
  1450.         if (iBand != -1)
  1451.             prbb = RBGETBAND(prb, iBand);
  1452.         if (prbbHotOld && (prbbHotOld->wChevState & DCHF_PUSHED))
  1453.             return;
  1454.         if (prbb && (rbht.flags & RBHT_CHEVRON))
  1455.         {
  1456.             SetCapture(hwnd);
  1457.             RBUpdateChevronState(prb, prbb, DCHF_HOT);
  1458.             if (prbb == prbbHotOld)
  1459.                 prbbHotOld = NULL;
  1460.         }
  1461.         if (prbbHotOld)
  1462.         {
  1463.             CCReleaseCapture(&prb->ci);
  1464.             RBUpdateChevronState(prb, prbbHotOld, DCHF_INACTIVE);
  1465.         }
  1466.     }
  1467. }
  1468. void RBOnPushChevron(HWND hwnd, PRB prb, PRBB prbb, LPARAM lParamNM)
  1469. {
  1470.     NMREBARCHEVRON nm;
  1471.     nm.uBand = RBBANDTOINDEX(prb, prbb);
  1472.     nm.wID = prbb->wID;
  1473.     nm.lParam = prbb->lParam;
  1474.     nm.lParamNM = lParamNM;
  1475.     CopyRect(&nm.rc, &prbb->rcChevron);
  1476.     if (RB_ISVERT(prb))
  1477.         FlipRect(&nm.rc);
  1478.     RBUpdateChevronState(prb, prbb, DCHF_PUSHED);
  1479.     CCReleaseCapture(&prb->ci);
  1480.     CCSendNotify(&prb->ci, RBN_CHEVRONPUSHED, &nm.hdr);
  1481.     RBUpdateChevronState(prb, prb->prbbHot, DCHF_INACTIVE);
  1482. }
  1483. LRESULT CALLBACK ReBarWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1484. {
  1485.     PRB     prb = (PRB) GetWindowPtr(hwnd, 0);
  1486.     int     iBand;
  1487.     // bail if no prb unless at creation time
  1488.     if (!prb && !(uMsg == WM_NCCREATE))
  1489.         goto CallDWP;
  1490.     switch (uMsg)
  1491.     {
  1492.     case WM_SETREDRAW:
  1493.         if (prb->ci.iVersion >= 5)
  1494.             RBSetRecalc(prb, BOOLFROMPTR(wParam));
  1495.         return RBSetRedraw(prb, BOOLFROMPTR(wParam));
  1496.     case WM_NCCREATE:
  1497. #define lpcs ((LPCREATESTRUCT) lParam)
  1498.         InitGlobalColors();
  1499.         if (!(prb = (PRB) LocalAlloc(LPTR, sizeof(RB))))
  1500.             return(0L);
  1501.         SetWindowPtr(hwnd, 0, prb);
  1502.  
  1503.         prb->iCapture = -1;
  1504.         prb->clrBk = CLR_NONE;
  1505.         prb->clrText = CLR_NONE;
  1506.         // Init the dwSize because we block-copy it back to the app
  1507.         prb->clrsc.dwSize = sizeof(COLORSCHEME);
  1508.         prb->clrsc.clrBtnHighlight = prb->clrsc.clrBtnShadow = CLR_DEFAULT;
  1509.         prb->fRedraw = TRUE;
  1510.         prb->fRecalc = TRUE;
  1511.         // note, zero init memory from above
  1512.         CIInitialize(&prb->ci, hwnd, lpcs);
  1513.         if (!(prb->ci.style & (CCS_TOP | CCS_NOMOVEY | CCS_BOTTOM)))
  1514.         {
  1515.             prb->ci.style |= CCS_TOP;
  1516.             SetWindowLong(hwnd, GWL_STYLE, prb->ci.style);
  1517.         }
  1518.         RBSetFont(prb, 0);
  1519.         if (lpcs->lpCreateParams)
  1520.             RBSetBarInfo(prb, (LPREBARINFO) (lpcs->lpCreateParams));
  1521. #undef lpcs
  1522.         return TRUE;
  1523.     case WM_DESTROY:
  1524.         RBDestroy(prb);
  1525.         SetWindowPtr(hwnd, 0, 0);
  1526.         break;
  1527.     case WM_CREATE:
  1528.         // Do delayed stuff for speed.
  1529.         PostMessage(hwnd, RB_PRIV_DODELAYEDSTUFF, 0, 0);
  1530.         goto CallDWP;
  1531.     case RB_PRIV_DODELAYEDSTUFF:
  1532.         // Delay done stuff for speed:
  1533.         if (prb->ci.style & RBS_REGISTERDROP)
  1534.             prb->hDragProxy = CreateDragProxy(prb->ci.hwnd, RebarDragCallback, TRUE);
  1535.                 
  1536.         if (prb->ci.style & RBS_TOOLTIPS)
  1537.         {
  1538.             TOOLINFO ti;
  1539.             // don't bother setting the rect because we'll do it below
  1540.             // in FlushToolTipsMgr;
  1541.             ti.cbSize = sizeof(ti);
  1542.             ti.uFlags = TTF_IDISHWND;
  1543.             ti.hwnd = hwnd;
  1544.             ti.uId = (UINT_PTR)hwnd;
  1545.             ti.lpszText = 0;
  1546.             prb->hwndToolTips = CreateWindow(c_szSToolTipsClass, NULL,
  1547.                     WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  1548.                     hwnd, NULL, (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), NULL);
  1549.             SendMessage(prb->hwndToolTips, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO) &ti);
  1550.         }
  1551.         RBInitPaletteHack(prb);
  1552.         break;
  1553.     case WM_NCHITTEST:
  1554.         {
  1555.             RBHITTESTINFO rbht;
  1556.             int iBand;
  1557.             
  1558.             rbht.pt.x = GET_X_LPARAM(lParam);
  1559.             rbht.pt.y = GET_Y_LPARAM(lParam);
  1560.             ScreenToClient(prb->ci.hwnd, &rbht.pt);
  1561.             iBand = RBHitTest(prb, &rbht);
  1562.             {
  1563.                 NMMOUSE nm;
  1564.                 LRESULT lres;
  1565.                 
  1566.                 nm.dwItemSpec = iBand;
  1567.                 nm.pt = rbht.pt;
  1568.                 nm.dwHitInfo = rbht.flags;
  1569.                 
  1570.                 // send to the parent to give them a chance to override
  1571.                 lres = CCSendNotify(&prb->ci, NM_NCHITTEST, &nm.hdr);
  1572.                 if (lres)
  1573.                     return lres;
  1574.                 
  1575.             }
  1576.         }
  1577.         return HTCLIENT;
  1578.     case WM_NCCALCSIZE:
  1579.         if (prb->ci.style & WS_BORDER)
  1580.         {
  1581.             InflateRect((LPRECT) lParam, -g_cxEdge, -g_cyEdge);
  1582.             break;
  1583.         }
  1584.         goto CallDWP;
  1585.     case WM_NCPAINT:
  1586.         if (prb->ci.style & WS_BORDER)
  1587.         {
  1588.             RECT rc;
  1589.             HDC hdc;
  1590.             GetWindowRect(hwnd, &rc);
  1591.             OffsetRect(&rc, -rc.left, -rc.top);
  1592.             hdc = GetWindowDC(hwnd);
  1593.             CCDrawEdge(hdc, &rc, EDGE_ETCHED, BF_RECT, &(prb->clrsc));
  1594.             ReleaseDC(hwnd, hdc);
  1595.             break;
  1596.         }
  1597.         goto CallDWP;
  1598.     case WM_PALETTECHANGED:
  1599.         if ((HWND)wParam == hwnd)
  1600.             break;
  1601.     case WM_QUERYNEWPALETTE:
  1602.         // Want to pass FALSE if WM_QUERYNEWPALETTE...
  1603.         RBRealize(prb, NULL, uMsg == WM_PALETTECHANGED, uMsg == WM_PALETTECHANGED);
  1604.         return TRUE;
  1605.     case WM_PAINT:
  1606.     case WM_PRINTCLIENT:
  1607.         RBPaint(prb, (HDC)wParam);
  1608.         break;
  1609.     case WM_ERASEBKGND:
  1610.         if (RBEraseBkgnd(prb, (HDC) wParam, -1))
  1611.             return(TRUE);
  1612.         goto CallDWP;
  1613.     case WM_SYSCOLORCHANGE:
  1614.         RBInitPaletteHack(prb);
  1615.         if (prb->hwndToolTips)
  1616.             SendMessage(prb->hwndToolTips, uMsg, wParam, lParam);
  1617.         InitGlobalColors();
  1618.         InvalidateRect(prb->ci.hwnd, NULL, TRUE);
  1619.         break;
  1620.     case RB_SETPALETTE:
  1621.         return (LRESULT)RBSetPalette(prb, (HPALETTE)lParam);
  1622.     case RB_GETPALETTE:
  1623.         return (LRESULT)prb->hpal;
  1624.     case WM_SIZE:
  1625.         RBAutoSize(prb);
  1626.         RBResize(prb, FALSE);
  1627.         break;
  1628.     case WM_GETFONT:
  1629.         return((LRESULT) (prb ? prb->hFont : NULL));
  1630.     case WM_COMMAND:
  1631.     case WM_DRAWITEM:
  1632.     case WM_MEASUREITEM:
  1633.     case WM_VKEYTOITEM:
  1634.     case WM_CHARTOITEM:
  1635.         SendMessage(prb->ci.hwndParent, uMsg, wParam, lParam);
  1636.         break;
  1637.     case WM_LBUTTONDBLCLK:  // DBLCLK sent in place of LBUTTONDOWN
  1638.     case WM_RBUTTONDOWN:    // right button drags too
  1639.     case WM_LBUTTONDOWN:
  1640.         {
  1641.             RBHITTESTINFO rbht;
  1642.             PRBB prbb = NULL;
  1643.             rbht.pt.x = GET_X_LPARAM(lParam);
  1644.             rbht.pt.y = GET_Y_LPARAM(lParam);
  1645.             RelayToToolTips(prb->hwndToolTips, hwnd, uMsg, wParam, lParam);
  1646.             iBand = RBHitTest(prb, &rbht);
  1647.             if (iBand != -1)
  1648.                 prbb = RBGETBAND(prb, iBand);
  1649.             if (!prbb)
  1650.                 /* nothing */ ;
  1651.             else if (rbht.flags & RBHT_CHEVRON)
  1652.             {
  1653.                 RBOnPushChevron(hwnd, prb, prbb, 0);
  1654.             }
  1655.             else if (rbht.flags != RBHT_CLIENT && RBShouldDrawGripper(prb, prbb))
  1656.             {
  1657.                 prb->iCapture = iBand;
  1658.                 prb->ptCapture = rbht.pt;
  1659.                 if (prb->ci.style & CCS_VERT) 
  1660.                     SWAP(prb->ptCapture.x, prb->ptCapture.y, int);
  1661.                 prb->xStart = prbb->x;
  1662.                 SetCapture(hwnd);
  1663.                 prb->fFullOnDrag = FALSE;
  1664.                 if (uMsg == WM_LBUTTONDBLCLK && (prb->ci.style & RBS_DBLCLKTOGGLE))
  1665.                     RBToggleBand(prb,TRUE);
  1666.             }
  1667.         }
  1668.         break;
  1669.     case WM_SETCURSOR:
  1670.         // Give the parent first crack, if it sets the cursor then
  1671.         // leave it at that.  Otherwise if the cursor is over our
  1672.         // window then set it to what we want it to be.
  1673.         if (!DefWindowProc(hwnd, uMsg, wParam, lParam) && (hwnd == (HWND)wParam))
  1674.         {
  1675.             POINT   pt;
  1676.             GetMessagePosClient(prb->ci.hwnd, &pt);
  1677.             RBSetCursor(prb, pt.x, pt.y,  (HIWORD(lParam) == WM_LBUTTONDOWN || HIWORD(lParam) == WM_RBUTTONDOWN));
  1678.         }
  1679.         return TRUE;
  1680.     case WM_MOUSEMOVE:
  1681.         RBOnMouseMove(hwnd, uMsg, wParam, lParam, prb);
  1682.         break;
  1683.     case WM_RBUTTONUP:
  1684.         if (!prb->fFullOnDrag && !prb->fParentDrag) {
  1685.             CCReleaseCapture(&prb->ci);
  1686.             // if we're not doing drag drop, go to def window proc so that
  1687.             // wm_contextmenu gets propagated
  1688.             RBOnBeginDrag(prb, (UINT)-1);
  1689.             goto CallDWP;
  1690.         }
  1691.         // fall through
  1692.     case WM_LBUTTONUP:
  1693.         RelayToToolTips(prb->hwndToolTips, hwnd, uMsg, wParam, lParam);
  1694.         if (prb->iCapture != -1)
  1695.         {
  1696.             UINT uiIndex;
  1697.             if (!prb->fParentDrag)
  1698.                 CCReleaseCapture(&prb->ci);
  1699.             // if there was no significant mouse motion, treat as a click
  1700.             if (!(prb->ci.style & RBS_DBLCLKTOGGLE) && !prb->fFullOnDrag)
  1701.                 RBToggleBand(prb,TRUE);
  1702.             RBGETBAND(prb, prb->iCapture)->fStyle &= ~RBBS_DRAGBREAK;
  1703.             CCSendNotify(&prb->ci, RBN_LAYOUTCHANGED, NULL);
  1704.             RBSendNotify(prb, prb->iCapture, RBN_ENDDRAG);
  1705.             RBOnBeginDrag(prb, (UINT)-1);
  1706.             for (uiIndex = 0; uiIndex < prb->cBands; uiIndex++) {
  1707.                 if (RBGETBAND(prb, uiIndex)->fStyle & RBBS_HIDDEN)
  1708.                     continue;
  1709.                 RBBCalcMinWidth(prb, RBGETBAND(prb, uiIndex));
  1710.             }
  1711.             RBSizeBandsToRect(prb, NULL);
  1712.             RBInvalidateRect(prb, NULL);
  1713.         }
  1714.         break;
  1715.     case WM_WININICHANGE:
  1716.         InitGlobalMetrics(wParam);
  1717.         if (prb->fFontCreated)
  1718.             RBSetFont(prb, wParam);
  1719.         if (prb->hwndToolTips)
  1720.             SendMessage(prb->hwndToolTips, uMsg, wParam, lParam);
  1721.         break;
  1722.     case WM_SETFONT:
  1723.         RBOnSetFont(prb, (HFONT)wParam);
  1724.         break;
  1725.     case WM_NOTIFYFORMAT:
  1726.         return(CIHandleNotifyFormat(&prb->ci, lParam));
  1727.     case WM_NOTIFY:
  1728.         // We are just going to pass this on to the real parent
  1729.         // Note that -1 is used as the hwndFrom.  This prevents SendNotifyEx
  1730.         // from updating the NMHDR structure.
  1731.         return(SendNotifyEx(prb->ci.hwndParent, (HWND) -1,
  1732.                  ((LPNMHDR) lParam)->code, (LPNMHDR) lParam, prb->ci.bUnicode));
  1733.     case WM_STYLECHANGED:
  1734.         RBOnStyleChanged(prb, wParam, (LPSTYLESTRUCT)lParam);
  1735.         break;
  1736. #ifdef KEYBOARDCUES
  1737.     case WM_UPDATEUISTATE:
  1738.         if (CCOnUIState(&(prb->ci), WM_UPDATEUISTATE, wParam, lParam))
  1739.         {
  1740.             InvalidateRect(hwnd, NULL, TRUE);
  1741.         }
  1742.         goto CallDWP;
  1743. #endif
  1744. #ifdef UNICODE
  1745.     case RB_SETBANDINFOA:
  1746.     case RB_INSERTBANDA:
  1747.         if (EVAL(lParam))
  1748.         {
  1749.             LPWSTR lpStrings = NULL;
  1750.             LPSTR  lpAnsiString;
  1751.             int    iResult;
  1752.             // lParam starts out pointing to a REBARBANDINFOA, and
  1753.             // we secretly change it into a REBARBANDINFOW, and then
  1754.             // change it back.
  1755.             LPREBARBANDINFOW prbiW = (LPREBARBANDINFOW)lParam;
  1756.             LPREBARBANDINFOA prbiA = (LPREBARBANDINFOA)lParam;
  1757.             COMPILETIME_ASSERT(sizeof(REBARBANDINFOW) == sizeof(REBARBANDINFOA));
  1758.             // BUGBUG - raymondc - Is it safe to modify the incoming
  1759.             // REBARBANDINFOA structure?
  1760.             lpAnsiString = prbiA->lpText;
  1761.             if ((prbiA->fMask & RBBIM_TEXT) && prbiA->lpText) {
  1762.                 lpStrings = ProduceWFromA(prb->ci.uiCodePage, lpAnsiString);
  1763.                 if (!lpStrings)
  1764.                     return -1;
  1765.                 // Presto!  Now it's a REBARBANDINFOW!
  1766.                 prbiW->lpText = lpStrings;
  1767.             }
  1768.             if (uMsg == RB_INSERTBANDA)
  1769.                 iResult = RBInsertBand(prb, (UINT) wParam, prbiW);
  1770.             else
  1771.                 iResult = RBSetBandInfo(prb, (UINT) wParam, prbiW, TRUE);
  1772.             // Change-o!  Now it's a REBARBANDINFOA!
  1773.             prbiA->lpText = lpAnsiString;
  1774.             if (lpStrings)
  1775.                 FreeProducedString(lpStrings);
  1776.             return iResult;
  1777.         }
  1778. #endif
  1779.     case RB_INSERTBAND:
  1780.         return(RBInsertBand(prb, (UINT) wParam, (LPREBARBANDINFO) lParam));
  1781.     case RB_DELETEBAND:
  1782.         return(RBDeleteBand(prb, (UINT) wParam));
  1783.     case RB_SHOWBAND:
  1784.         return(RBShowBand(prb, (UINT) wParam, BOOLFROMPTR(lParam)));
  1785. #ifdef UNICODE
  1786.     case RB_GETBANDINFOA:
  1787.         {
  1788.             LPREBARBANDINFOA prbbi = (LPREBARBANDINFOA)lParam;
  1789.             LPWSTR pszW = NULL;
  1790.             LPSTR  lpAnsiString = prbbi->lpText;
  1791.             int    iResult;
  1792.             if (prbbi->fMask & RBBIM_TEXT) {
  1793.                 pszW = LocalAlloc(LPTR, prbbi->cch * sizeof(WCHAR));
  1794.                 if (!pszW)
  1795.                     return 0;
  1796.                 prbbi->lpText = (LPSTR)pszW;
  1797.             }
  1798.             iResult = RBGetBandInfo(prb, (UINT)wParam, (LPREBARBANDINFO)lParam);
  1799.             if (pszW) {
  1800.                 ConvertWToAN(prb->ci.uiCodePage, lpAnsiString, prbbi->cch, (LPWSTR)prbbi->lpText, -1);
  1801.                 prbbi->lpText = lpAnsiString;
  1802.                 LocalFree(pszW);
  1803.             }
  1804.             return iResult;
  1805.         }
  1806. #endif
  1807.         // we have getbandinfoold because in ie3, we did not thunk
  1808.         // and getbandinfo always return OS native string (dumb)
  1809.     case RB_GETBANDINFOOLD:
  1810.     case RB_GETBANDINFO:
  1811.         return(RBGetBandInfo(prb, (UINT) wParam, (LPREBARBANDINFO) lParam));
  1812.             
  1813.     case RB_GETTOOLTIPS:
  1814.         return (LPARAM)prb->hwndToolTips;
  1815.             
  1816.     case RB_SETTOOLTIPS:
  1817.         prb->hwndToolTips = (HWND)wParam;
  1818.         break;
  1819.             
  1820.     case RB_SETBKCOLOR:
  1821.         {
  1822.             COLORREF clr = prb->clrBk;
  1823.             prb->clrBk = (COLORREF)lParam;
  1824.             if (clr != prb->clrBk)
  1825.                 InvalidateRect(prb->ci.hwnd, NULL, TRUE);
  1826.             return clr;
  1827.         }
  1828.             
  1829.     case RB_GETBKCOLOR:
  1830.         return prb->clrBk;
  1831.             
  1832.     case RB_SETTEXTCOLOR:
  1833.         {
  1834.             COLORREF clr = prb->clrText;
  1835.             prb->clrText = (COLORREF)lParam;
  1836.             return clr;
  1837.         }
  1838.             
  1839.     case RB_GETTEXTCOLOR:
  1840.         return prb->clrText;
  1841.     case RB_IDTOINDEX:
  1842.         return RBIDToIndex(prb, (UINT) wParam);
  1843.     case RB_GETROWCOUNT:
  1844.         return(RBGetRowCount(prb));
  1845.     case RB_GETROWHEIGHT:
  1846.         return RBGetRowHeight(prb, (UINT)wParam);
  1847.         
  1848.     case RB_GETBANDBORDERS:
  1849.         return RBGetBandBorders(prb, (UINT)wParam, (LPRECT)lParam);
  1850.     case RB_GETBANDCOUNT:
  1851.         return(prb->cBands);
  1852.     case RB_SETBANDINFO:
  1853.         return(RBSetBandInfo(prb, (UINT) wParam, (LPREBARBANDINFO) lParam, TRUE));
  1854.     case RB_GETBARINFO:
  1855.         return(RBGetBarInfo(prb, (LPREBARINFO) lParam));
  1856.     case RB_SETBARINFO:
  1857.         return(RBSetBarInfo(prb, (LPREBARINFO) lParam));
  1858.     case RB_SETPARENT:
  1859.         {
  1860.             HWND hwndOld = prb->ci.hwndParent;
  1861.             prb->ci.hwndParent = (HWND) wParam;
  1862.             return (LRESULT)hwndOld;
  1863.         }
  1864.         break;
  1865.     case RB_GETRECT:
  1866.         if (RB_ISVALIDINDEX(prb, wParam))
  1867.         {
  1868.             PRBB prbb = RBGETBAND(prb, (int) wParam);
  1869.             LPRECT lprc = (LPRECT) lParam;
  1870.             lprc->left = prbb->x;
  1871.             lprc->top = prbb->y;
  1872.             lprc->right = prbb->x + prbb->cx;
  1873.             lprc->bottom = prbb->y + prbb->cy;
  1874.             return(TRUE);
  1875.         }
  1876.         break;
  1877.     case RB_HITTEST:
  1878.         return(RBHitTest(prb, (LPRBHITTESTINFO) lParam));
  1879.     case RB_SIZETORECT:
  1880.         return RBSizeBarToRect(prb, (LPRECT)lParam);
  1881.     case RB_BEGINDRAG:
  1882.         if (RB_ISVALIDINDEX(prb, wParam)) {
  1883.             // -1 means do it yourself.
  1884.             // -2 means use what you had saved before
  1885.             if (lParam != (LPARAM)-2) {
  1886.                 if (lParam == (LPARAM)-1) {
  1887.                     GetMessagePosClient(prb->ci.hwnd, &prb->ptCapture);
  1888.                 } else {
  1889.                     prb->ptCapture.x = GET_X_LPARAM(lParam);
  1890.                     prb->ptCapture.y = GET_Y_LPARAM(lParam);
  1891.                 }
  1892.                 if (prb->ci.style & CCS_VERT) 
  1893.                     SWAP(prb->ptCapture.x, prb->ptCapture.y, int);
  1894.             }
  1895.             prb->xStart = RBGETBAND(prb, (UINT)wParam)->x;
  1896.             RBOnBeginDrag(prb, (UINT)wParam);
  1897.         }
  1898.         break;
  1899.         
  1900.     case RB_GETBARHEIGHT:
  1901.         return RBGETBARHEIGHT(prb);
  1902.         
  1903.     case RB_ENDDRAG:
  1904.         RBOnBeginDrag(prb, (UINT)-1);
  1905.         break;
  1906.         
  1907.     case RB_DRAGMOVE:
  1908.         if (prb->iCapture != -1) {
  1909.             if (lParam == (LPARAM)-1) {
  1910.                 lParam = GetMessagePosClient(prb->ci.hwnd, NULL);
  1911.             }
  1912.             RBDragBand(prb, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  1913.         }
  1914.         break;
  1915.         
  1916.     case RB_MINIMIZEBAND:
  1917.         RBMinimizeBand(prb, (UINT) wParam,FALSE);
  1918.         break;
  1919.     case RB_MAXIMIZEBAND:
  1920.         RBMaximizeBand(prb, (UINT)wParam, BOOLFROMPTR(lParam),FALSE);
  1921.         break;
  1922.     case RB_MOVEBAND:
  1923.         if (!RB_ISVALIDINDEX(prb,wParam) || !RB_ISVALIDINDEX(prb,lParam))
  1924.             break;
  1925.         return RBMoveBand(prb, (UINT) wParam, (UINT) lParam);
  1926.     case RB_GETDROPTARGET:
  1927.         if (!prb->hDragProxy)
  1928.             prb->hDragProxy = CreateDragProxy(prb->ci.hwnd, RebarDragCallback, FALSE);
  1929.         GetDragProxyTarget(prb->hDragProxy, (IDropTarget**)lParam);
  1930.         break;
  1931.     case RB_GETCOLORSCHEME:
  1932.         {
  1933.             LPCOLORSCHEME lpclrsc = (LPCOLORSCHEME) lParam;
  1934.             if (lpclrsc) {
  1935.                 if (lpclrsc->dwSize == sizeof(COLORSCHEME))
  1936.                     *lpclrsc = prb->clrsc;
  1937.             }
  1938.             return (LRESULT) lpclrsc;
  1939.         }
  1940.     case RB_SETCOLORSCHEME:
  1941.         if (lParam) {
  1942.             if (((LPCOLORSCHEME) lParam)->dwSize == sizeof(COLORSCHEME)) {
  1943.                 prb->clrsc.clrBtnHighlight = ((LPCOLORSCHEME) lParam)->clrBtnHighlight;
  1944.                 prb->clrsc.clrBtnShadow = ((LPCOLORSCHEME) lParam)->clrBtnShadow;        
  1945.                 InvalidateRect(hwnd, NULL, FALSE);
  1946.                 if (prb->ci.style & WS_BORDER)
  1947.                     CCInvalidateFrame(hwnd);
  1948.             }
  1949.         }
  1950.         break;
  1951.     case RB_PUSHCHEVRON:
  1952.         if (RB_ISVALIDINDEX(prb, wParam)) {
  1953.             PRBB prbb = RBGETBAND(prb, wParam);
  1954.             RBOnPushChevron(hwnd, prb, prbb, lParam);
  1955.         }
  1956.         break;
  1957.     default:
  1958.         {
  1959.             LRESULT lres;
  1960.             if (CCWndProc(&prb->ci, uMsg, wParam, lParam, &lres))
  1961.                 return lres;
  1962.         }
  1963.         
  1964. CallDWP:
  1965.         return(DefWindowProc(hwnd, uMsg, wParam, lParam));
  1966.     }
  1967.     return(0L);
  1968. }