comctl32: rebar: rewrite the layouting code

Mikołaj Zalewski mikolaj at zalewski.pl
Sun Feb 4 17:40:53 CST 2007


I've been trying to fix the rebar layouting code. But fixes in one place 
caused regressions because of bugs in other places and I ended up 
rewriting the whole layouting code. It does roughly the same as the 
current code however the details are quite different and I hope more 
correct. It's also much shorter so it should be earier to 
understand/debug. My code work for me for all apps I tested (except for 
the sidebars of IE but I'm trying to find out why). It also passes some 
tests I've written and produces identical results that the native. Two 
things could be potentially better in the old code:
  - it contains some support for RBBS_FIXEDSIZE (however different from 
what Windows does)
  - it can break rows to fill the given space (but that should be only 
done for RBS_AUTOSIZE rebars)

  I have yet to test the REBAR_Maximize and REBAR_Minimize but I have 
two questions. Does this code cause regressions in apps that works with 
the current code and would such big patch be accepted?
-------------- next part --------------
From 30c988e5b0f3e1c1f5de97deaf3629f93cde15e6 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Miko=C5=82aj_Zalewski?= <mikolaj at zalewski.pl>
Date: Sun, 4 Feb 2007 18:51:40 +0100
Subject: [PATCH] comctl32: rebar: rewrite the layouting code

---
 dlls/comctl32/rebar.c       | 1718 +++++++++++++------------------------------
 dlls/comctl32/tests/rebar.c |  352 +++++++++-
 2 files changed, 832 insertions(+), 1238 deletions(-)

diff --git a/dlls/comctl32/rebar.c b/dlls/comctl32/rebar.c
index 9550eb5..5407c83 100644
--- a/dlls/comctl32/rebar.c
+++ b/dlls/comctl32/rebar.c
@@ -127,14 +127,10 @@ typedef struct
     LPARAM    lParam;
     UINT    cxHeader;
 
+    INT     cxEffective;     /* current cx for band */
     UINT    lcx;            /* minimum cx for band */
-    UINT    ccx;            /* current cx for band */
-    UINT    hcx;            /* maximum cx for band */
     UINT    lcy;            /* minimum cy for band */
-    UINT    ccy;            /* current cy for band */
-    UINT    hcy;            /* maximum cy for band */
 
-    SIZE    offChild;       /* x,y offset if child is not FIXEDSIZE */
     UINT    uMinHeight;
     INT     iRow;           /* zero-based index of the row this band assigned to */
     UINT    fStatus;        /* status flags, reset only by _Validate */
@@ -161,12 +157,8 @@ typedef struct
 #define DRAW_GRIPPER    0x00000001
 #define DRAW_IMAGE      0x00000002
 #define DRAW_TEXT       0x00000004
-#define DRAW_RIGHTSEP   0x00000010
-#define DRAW_BOTTOMSEP  0x00000020
 #define DRAW_CHEVRONHOT 0x00000040
 #define DRAW_CHEVRONPUSHED 0x00000080
-#define DRAW_LAST_IN_ROW   0x00000100
-#define DRAW_FIRST_IN_ROW  0x00000200
 #define NTF_INVALIDATE  0x01000000
 
 typedef struct
@@ -250,10 +242,16 @@ typedef struct
 /* Width of the chevron button if present */
 #define CHEVRON_WIDTH  10
 
+/* the gap between the child and the next band */
+#define REBAR_POST_CHILD 4
+
 /* Height of divider for Rebar if not disabled (CCS_NODIVIDER)     */
 /* either top or bottom                                            */
 #define REBAR_DIVIDER  2
 
+/* height of a rebar without a child */
+#define REBAR_NO_CHILD_HEIGHT 4
+
 /* minimium vertical height of a normal bar                        */
 /*   or minimum width of a CCS_VERT bar - from experiment on Win2k */
 #define REBAR_MINSIZE  23
@@ -265,29 +263,11 @@ typedef struct
 
 #define RB_GETBANDINFO_OLD (WM_USER+5) /* obsoleted after IE3, but we have to support it anyway */
 
-/*  The following 6 defines return the proper rcBand element       */
-/*  depending on whether CCS_VERT was set.                         */
-#define rcBlt(b) ((infoPtr->dwStyle & CCS_VERT) ? b->rcBand.top : b->rcBand.left)
-#define rcBrb(b) ((infoPtr->dwStyle & CCS_VERT) ? b->rcBand.bottom : b->rcBand.right)
-#define rcBw(b)  ((infoPtr->dwStyle & CCS_VERT) ? (b->rcBand.bottom - b->rcBand.top) : \
-		  (b->rcBand.right - b->rcBand.left))
-#define ircBlt(b) ((infoPtr->dwStyle & CCS_VERT) ? b->rcBand.left : b->rcBand.top)
-#define ircBrb(b) ((infoPtr->dwStyle & CCS_VERT) ? b->rcBand.right : b->rcBand.bottom)
-#define ircBw(b)  ((infoPtr->dwStyle & CCS_VERT) ? (b->rcBand.right - b->rcBand.left) : \
-		  (b->rcBand.bottom - b->rcBand.top))
-
 /*  The following define determines if a given band is hidden      */
 #define HIDDENBAND(a)  (((a)->fStyle & RBBS_HIDDEN) ||   \
                         ((infoPtr->dwStyle & CCS_VERT) &&         \
                          ((a)->fStyle & RBBS_NOVERT)))
 
-/*  The following defines adjust the right or left end of a rectangle */
-#define READJ(b,i) do { if(infoPtr->dwStyle & CCS_VERT) b->rcBand.bottom+=(i); \
-                    else b->rcBand.right += (i); } while(0)
-#define LEADJ(b,i) do { if(infoPtr->dwStyle & CCS_VERT) b->rcBand.top+=(i); \
-                    else b->rcBand.left += (i); } while(0)
-
-
 #define REBAR_GetInfoPtr(wndPtr) ((REBAR_INFO *)GetWindowLongPtrW (hwnd, 0))
 
 static LRESULT REBAR_NotifyFormat(REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam);
@@ -446,8 +426,8 @@ REBAR_DumpBand (REBAR_INFO *iP)
 	if (pB->fMask & RBBIM_TEXT)
 	    TRACE("band # %u: text=%s\n",
 		  i, (pB->lpText) ? debugstr_w(pB->lpText) : "(null)");
-	TRACE("band # %u: lcx=%u, ccx=%u, hcx=%u, lcy=%u, ccy=%u, hcy=%u, offChild=%d,%d\n",
-	      i, pB->lcx, pB->ccx, pB->hcx, pB->lcy, pB->ccy, pB->hcy, pB->offChild.cx, pB->offChild.cy);
+	TRACE("band # %u: lcx=%u, cxEffective=%u, lcy=%u\n",
+	      i, pB->lcx, pB->cxEffective, pB->lcy);
 	TRACE("band # %u: fStatus=%08x, fDraw=%08x, Band=(%d,%d)-(%d,%d), Grip=(%d,%d)-(%d,%d)\n",
 	      i, pB->fStatus, pB->fDraw,
 	      pB->rcBand.left, pB->rcBand.top, pB->rcBand.right, pB->rcBand.bottom,
@@ -461,6 +441,43 @@ REBAR_DumpBand (REBAR_INFO *iP)
 
 }
 
+static void translate_rect(REBAR_INFO *infoPtr, RECT *dest, const RECT *src)
+{
+    if (infoPtr->dwStyle & CCS_VERT) {
+        dest->top = src->left;
+        dest->bottom = src->right;
+        dest->left = src->top;
+        dest->right = src->bottom;
+    } else {
+        *dest = *src;
+    }
+}
+
+static int get_rect_cx(REBAR_INFO *infoPtr, RECT *lpRect)
+{
+    if (infoPtr->dwStyle & CCS_VERT)
+        return lpRect->bottom - lpRect->top;
+    return lpRect->right - lpRect->left;
+}
+
+static int get_rect_cy(REBAR_INFO *infoPtr, RECT *lpRect)
+{
+    if (infoPtr->dwStyle & CCS_VERT)
+        return lpRect->right - lpRect->left;
+    return lpRect->bottom - lpRect->top;
+}
+
+static void round_child_height(REBAR_BAND *lpBand, int cyHeight)
+{
+    int cy = 0;
+    if (lpBand->cyIntegral == 0)
+        return;
+    cy = max(cyHeight - (int)lpBand->cyMinChild, 0);
+    cy = lpBand->cyMinChild + (cy/lpBand->cyIntegral) * lpBand->cyIntegral;
+    cy = min(cy, lpBand->cyMaxChild);
+    lpBand->cyChild = cy;
+}
+
 static void
 REBAR_DrawChevron (HDC hdc, INT left, INT top, INT colorRef)
 {
@@ -544,6 +561,9 @@ REBAR_DrawBand (HDC hdc, REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
     INT oldBkMode = 0;
     NMCUSTOMDRAW nmcd;
     HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
+    RECT rcBand;
+
+    translate_rect(infoPtr, &rcBand, &lpBand->rcBand);
 
     if (lpBand->fDraw & DRAW_TEXT) {
 	hOldFont = SelectObject (hdc, infoPtr->hFont);
@@ -553,7 +573,7 @@ REBAR_DrawBand (HDC hdc, REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
     /* should test for CDRF_NOTIFYITEMDRAW here */
     nmcd.dwDrawStage = CDDS_ITEMPREPAINT;
     nmcd.hdc = hdc;
-    nmcd.rc = lpBand->rcBand;
+    nmcd.rc = rcBand;
     nmcd.rc.right = lpBand->rcCapText.right;
     nmcd.rc.bottom = lpBand->rcCapText.bottom;
     nmcd.dwItemSpec = lpBand->wID;
@@ -649,7 +669,7 @@ REBAR_DrawBand (HDC hdc, REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
     if (lpBand->uCDret == (CDRF_NOTIFYPOSTPAINT | CDRF_NOTIFYITEMDRAW)) {
 	nmcd.dwDrawStage = CDDS_ITEMPOSTPAINT;
 	nmcd.hdc = hdc;
-	nmcd.rc = lpBand->rcBand;
+	nmcd.rc = rcBand;
 	nmcd.rc.right = lpBand->rcCapText.right;
 	nmcd.rc.bottom = lpBand->rcCapText.bottom;
 	nmcd.dwItemSpec = lpBand->wID;
@@ -683,235 +703,14 @@ REBAR_Refresh (REBAR_INFO *infoPtr, HDC hdc)
 
 
 static void
-REBAR_FixVert (REBAR_INFO *infoPtr, UINT rowstart, UINT rowend,
-		   INT mcy)
-     /* Function:                                                    */
-     /*   Cycle through bands in row and fix height of each band.    */
-     /*   Also determine whether each band has changed.              */
-     /* On entry:                                                    */
-     /*   all bands at desired size.                                 */
-     /*   start and end bands are *not* hidden                       */
-{
-    REBAR_BAND *lpBand;
-    INT i;
-
-    for (i = (INT)rowstart; i<=(INT)rowend; i++) {
-        lpBand = &infoPtr->bands[i];
-	if (HIDDENBAND(lpBand)) continue;
-
-	/* adjust height of bands in row to "mcy" value */
-	if (infoPtr->dwStyle & CCS_VERT) {
-	    if (lpBand->rcBand.right != lpBand->rcBand.left + mcy)
-	        lpBand->rcBand.right = lpBand->rcBand.left + mcy;
-	}
-	else {
-	    if (lpBand->rcBand.bottom != lpBand->rcBand.top + mcy)
-	        lpBand->rcBand.bottom = lpBand->rcBand.top + mcy;
-
-	}
-
-	/* mark whether we need to invalidate this band and trace */
-	if ((lpBand->rcoldBand.left !=lpBand->rcBand.left) ||
-	    (lpBand->rcoldBand.top !=lpBand->rcBand.top) ||
-	    (lpBand->rcoldBand.right !=lpBand->rcBand.right) ||
-	    (lpBand->rcoldBand.bottom !=lpBand->rcBand.bottom)) {
-	    lpBand->fDraw |= NTF_INVALIDATE;
-            TRACE("band %d row=%d: changed to (%d,%d)-(%d,%d) from (%d,%d)-(%d,%d)\n",
-		  i, lpBand->iRow,
-		  lpBand->rcBand.left, lpBand->rcBand.top,
-		  lpBand->rcBand.right, lpBand->rcBand.bottom,
-		  lpBand->rcoldBand.left, lpBand->rcoldBand.top,
-		  lpBand->rcoldBand.right, lpBand->rcoldBand.bottom);
-	}
-	else
-            TRACE("band %d row=%d: unchanged (%d,%d)-(%d,%d)\n",
-		  i, lpBand->iRow,
-		  lpBand->rcBand.left, lpBand->rcBand.top,
-		  lpBand->rcBand.right, lpBand->rcBand.bottom);
-    }
-}
-
-
-static void
-REBAR_AdjustBands (REBAR_INFO *infoPtr, UINT rowstart, UINT rowend,
-		   INT maxx, INT mcy)
-     /* Function: This routine distributes the extra space in a row. */
-     /*  See algorithm below.                                        */
-     /* On entry:                                                    */
-     /*   all bands @ ->cxHeader size                                */
-     /*   start and end bands are *not* hidden                       */
-{
-    REBAR_BAND *lpBand;
-    UINT xsep, extra, curwidth, fudge;
-    INT x, i, last_adjusted;
-
-    TRACE("start=%u, end=%u, max x=%d, max y=%d\n",
-	  rowstart, rowend, maxx, mcy);
-
-    /* *******************  Phase 1  ************************ */
-    /* Alg:                                                   */
-    /*  For each visible band with valid child                */
-    /*      a. inflate band till either all extra space used  */
-    /*         or band's ->ccx reached.                       */
-    /*  If any band modified, add any space left to last band */
-    /*  adjusted.                                             */
-    /*                                                        */
-    /* ****************************************************** */
-    lpBand = &infoPtr->bands[rowend];
-    extra = maxx - rcBrb(lpBand);
-    x = 0;
-    last_adjusted = -1;
-    for (i=(INT)rowstart; i<=(INT)rowend; i++) {
-	lpBand = &infoPtr->bands[i];
-	if (HIDDENBAND(lpBand)) continue;
-	xsep = (x == 0) ? 0 : SEP_WIDTH;
-	curwidth = rcBw(lpBand);
-
-	/* set new left/top point */
-	if (infoPtr->dwStyle & CCS_VERT)
-	    lpBand->rcBand.top = x + xsep;
-	else
-	    lpBand->rcBand.left = x + xsep;
-
-	/* compute new width */
-	if ((lpBand->hwndChild && extra) && !(lpBand->fStyle & RBBS_FIXEDSIZE)) {
-	    /* set to the "current" band size less the header */
-	    fudge = lpBand->ccx;
-	    last_adjusted = i;
-	    if ((lpBand->fMask & RBBIM_SIZE) && (lpBand->cx > 0) &&
-		(fudge > curwidth)) {
-		TRACE("adjusting band %d by %d, fudge=%d, curwidth=%d, extra=%d\n",
-		      i, fudge-curwidth, fudge, curwidth, extra);
-		if ((fudge - curwidth) > extra)
-		    fudge = curwidth + extra;
-		extra -= (fudge - curwidth);
-		curwidth = fudge;
-	    }
-	    else {
-		TRACE("adjusting band %d by %d, fudge=%d, curwidth=%d\n",
-		      i, extra, fudge, curwidth);
-		curwidth += extra;
-		extra = 0;
-	    }
-	}
-
-	/* set new right/bottom point */
-	if (infoPtr->dwStyle & CCS_VERT)
-	    lpBand->rcBand.bottom = lpBand->rcBand.top + curwidth;
-	else
-	    lpBand->rcBand.right = lpBand->rcBand.left + curwidth;
-	TRACE("Phase 1 band %d, (%d,%d)-(%d,%d), orig x=%d, xsep=%d\n",
-	      i, lpBand->rcBand.left, lpBand->rcBand.top,
-	      lpBand->rcBand.right, lpBand->rcBand.bottom, x, xsep);
-	x = rcBrb(lpBand);
-    }
-    if ((x >= maxx) || (last_adjusted != -1)) {
-	if (x > maxx) {
-	    ERR("Phase 1 failed, x=%d, maxx=%d, start=%u, end=%u\n",
-		x, maxx,  rowstart, rowend);
-	}
-	/* done, so spread extra space */
-	if (x < maxx) {
-	    fudge = maxx - x;
-	    TRACE("Need to spread %d on last adjusted band %d\n",
-		fudge, last_adjusted);
-	    for (i=(INT)last_adjusted; i<=(INT)rowend; i++) {
-		lpBand = &infoPtr->bands[i];
-		if (HIDDENBAND(lpBand)) continue;
-
-		/* set right/bottom point */
-		if (i != last_adjusted) {
-		    if (infoPtr->dwStyle & CCS_VERT)
-			lpBand->rcBand.top += fudge;
-		    else
-			lpBand->rcBand.left += fudge;
-		}
-
-		/* set left/bottom point */
-		if (infoPtr->dwStyle & CCS_VERT)
-		    lpBand->rcBand.bottom += fudge;
-		else
-		    lpBand->rcBand.right += fudge;
-	    }
-	}
-	TRACE("Phase 1 succeeded, used x=%d\n", x);
-	REBAR_FixVert (infoPtr, rowstart, rowend, mcy);
- 	return;
-    }
-
-    /* *******************  Phase 2  ************************ */
-    /* Alg:                                                   */
-    /*  Find first visible band, put all                      */
-    /*    extra space there.                                  */
-    /*                                                        */
-    /* ****************************************************** */
-
-    x = 0;
-    for (i=(INT)rowstart; i<=(INT)rowend; i++) {
-	lpBand = &infoPtr->bands[i];
-	if (HIDDENBAND(lpBand)) continue;
-	xsep = (x == 0) ? 0 : SEP_WIDTH;
-	curwidth = rcBw(lpBand);
-
-	/* set new left/top point */
-	if (infoPtr->dwStyle & CCS_VERT)
-	    lpBand->rcBand.top = x + xsep;
-	else
-	    lpBand->rcBand.left = x + xsep;
-
-	/* compute new width */
-	if (extra) {
-	    curwidth += extra;
-	    extra = 0;
-	}
-
-	/* set new right/bottom point */
-	if (infoPtr->dwStyle & CCS_VERT)
-	    lpBand->rcBand.bottom = lpBand->rcBand.top + curwidth;
-	else
-	    lpBand->rcBand.right = lpBand->rcBand.left + curwidth;
-	TRACE("Phase 2 band %d, (%d,%d)-(%d,%d), orig x=%d, xsep=%d\n",
-	      i, lpBand->rcBand.left, lpBand->rcBand.top,
-	      lpBand->rcBand.right, lpBand->rcBand.bottom, x, xsep);
-	x = rcBrb(lpBand);
-    }
-    if (x >= maxx) {
-	if (x > maxx) {
-	    ERR("Phase 2 failed, x=%d, maxx=%d, start=%u, end=%u\n",
-		x, maxx,  rowstart, rowend);
-	}
-	/* done, so spread extra space */
-	TRACE("Phase 2 succeeded, used x=%d\n", x);
-	REBAR_FixVert (infoPtr, rowstart, rowend, mcy);
-	return;
-    }
-
-    /* *******************  Phase 3  ************************ */
-    /* at this point everything is back to ->cxHeader values  */
-    /* and should not have gotten here.                       */
-    /* ****************************************************** */
-
-    lpBand = &infoPtr->bands[rowstart];
-    ERR("Serious problem adjusting row %d, start band %d, end band %d\n",
-	lpBand->iRow, rowstart, rowend);
-    REBAR_DumpBand (infoPtr);
-    return;
-}
-
-
-static void
-REBAR_CalcHorzBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify)
+REBAR_CalcHorzBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend)
      /* Function: this routine initializes all the rectangles in */
      /*  each band in a row to fit in the adjusted rcBand rect.  */
      /* *** Supports only Horizontal bars. ***                   */
 {
     REBAR_BAND *lpBand;
     UINT i, xoff, yoff;
-    HWND parenthwnd;
-    RECT oldChild, work;
-
-    /* MS seems to use GetDlgCtrlID() for above GetWindowLong call */
-    parenthwnd = GetParent (infoPtr->hwndSelf);
+    RECT work;
 
     for(i=rstart; i<rend; i++){
       lpBand = &infoPtr->bands[i];
@@ -922,8 +721,6 @@ REBAR_CalcHorzBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify)
 	  continue;
       }
 
-      oldChild = lpBand->rcChild;
-
       /* set initial gripper rectangle */
       SetRect (&lpBand->rcGripper, lpBand->rcBand.left, lpBand->rcBand.top,
 	       lpBand->rcBand.left, lpBand->rcBand.bottom);
@@ -980,12 +777,12 @@ REBAR_CalcHorzBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify)
       }
 
       /* set initial child window rectangle if there is a child */
-      if (lpBand->fMask & RBBIM_CHILD) {
-	  xoff = lpBand->offChild.cx;
-	  yoff = lpBand->offChild.cy;
+      if (lpBand->hwndChild != NULL) {
+          int cyBand = lpBand->rcBand.bottom - lpBand->rcBand.top;
+          yoff = (cyBand - lpBand->cyChild) / 2;
 	  SetRect (&lpBand->rcChild,
-		   lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.top+yoff,
-		   lpBand->rcBand.right-xoff, lpBand->rcBand.bottom-yoff);
+                   lpBand->rcBand.left + lpBand->cxHeader, lpBand->rcBand.top + yoff,
+                   lpBand->rcBand.right - REBAR_POST_CHILD, lpBand->rcBand.top + yoff + lpBand->cyChild);
 	  if ((lpBand->fStyle & RBBS_USECHEVRON) && (lpBand->rcChild.right - lpBand->rcChild.left < lpBand->cxIdeal))
 	  {
 	      lpBand->rcChild.right -= CHEVRON_WIDTH;
@@ -1001,26 +798,16 @@ REBAR_CalcHorzBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify)
       }
 
       /* flag if notify required and invalidate rectangle */
-      if (notify &&
-	  ((oldChild.right-oldChild.left != lpBand->rcChild.right-lpBand->rcChild.left) ||
-	   (oldChild.bottom-oldChild.top != lpBand->rcChild.bottom-lpBand->rcChild.top))) {
-	  TRACE("Child rectangle changed for band %u\n", i);
-          TRACE("    from (%d,%d)-(%d,%d)  to (%d,%d)-(%d,%d)\n",
-		oldChild.left, oldChild.top,
-	        oldChild.right, oldChild.bottom,
-		lpBand->rcChild.left, lpBand->rcChild.top,
-	        lpBand->rcChild.right, lpBand->rcChild.bottom);
-      }
       if (lpBand->fDraw & NTF_INVALIDATE) {
           TRACE("invalidating (%d,%d)-(%d,%d)\n",
 		lpBand->rcBand.left,
 		lpBand->rcBand.top,
-		lpBand->rcBand.right + ((lpBand->fDraw & DRAW_RIGHTSEP) ? SEP_WIDTH_SIZE : 0),
-		lpBand->rcBand.bottom + ((lpBand->fDraw & DRAW_BOTTOMSEP) ? SEP_WIDTH_SIZE : 0));
+		lpBand->rcBand.right + SEP_WIDTH,
+		lpBand->rcBand.bottom + SEP_WIDTH);
 	  lpBand->fDraw &= ~NTF_INVALIDATE;
 	  work = lpBand->rcBand;
-	  if (lpBand->fDraw & DRAW_RIGHTSEP) work.right += SEP_WIDTH_SIZE;
-	  if (lpBand->fDraw & DRAW_BOTTOMSEP) work.bottom += SEP_WIDTH_SIZE;
+	  work.right += SEP_WIDTH;
+	  work.bottom += SEP_WIDTH;
 	  InvalidateRect(infoPtr->hwndSelf, &work, TRUE);
       }
 
@@ -1030,27 +817,24 @@ REBAR_CalcHorzBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify)
 
 
 static VOID
-REBAR_CalcVertBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify)
+REBAR_CalcVertBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend)
      /* Function: this routine initializes all the rectangles in */
      /*  each band in a row to fit in the adjusted rcBand rect.  */
      /* *** Supports only Vertical bars. ***                     */
 {
     REBAR_BAND *lpBand;
-    UINT i, xoff, yoff;
-    HWND parenthwnd;
-    RECT oldChild, work;
-
-    /* MS seems to use GetDlgCtrlID() for above GetWindowLong call */
-    parenthwnd = GetParent (infoPtr->hwndSelf);
+    UINT i, xoff;
+    RECT work;
 
     for(i=rstart; i<rend; i++){
-	lpBand = &infoPtr->bands[i];
+        RECT rcBand;
+        lpBand = &infoPtr->bands[i];
 	if (HIDDENBAND(lpBand)) continue;
-	oldChild = lpBand->rcChild;
 
-	/* set initial gripper rectangle */
-	SetRect (&lpBand->rcGripper, lpBand->rcBand.left, lpBand->rcBand.top,
-		 lpBand->rcBand.right, lpBand->rcBand.top);
+        translate_rect(infoPtr, &rcBand, &lpBand->rcBand);
+
+        /* set initial gripper rectangle */
+	SetRect (&lpBand->rcGripper, rcBand.left, rcBand.top, rcBand.right, rcBand.top);
 
 	/* calculate gripper rectangle */
 	if (lpBand->fStatus & HAS_GRIPPER) {
@@ -1064,9 +848,9 @@ REBAR_CalcVertBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify)
 		lpBand->rcGripper.bottom = lpBand->rcGripper.top + GRIPPER_HEIGHT;
 
 		/* initialize Caption image rectangle  */
-		SetRect (&lpBand->rcCapImage, lpBand->rcBand.left,
+		SetRect (&lpBand->rcCapImage, rcBand.left,
 			 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE,
-			 lpBand->rcBand.right,
+			 rcBand.right,
 			 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE);
 	    }
 	    else {
@@ -1077,9 +861,9 @@ REBAR_CalcVertBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify)
 		lpBand->rcGripper.bottom  = lpBand->rcGripper.top + GRIPPER_WIDTH;
 
 		/* initialize Caption image rectangle  */
-		SetRect (&lpBand->rcCapImage, lpBand->rcBand.left,
+		SetRect (&lpBand->rcCapImage, rcBand.left,
 			 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE,
-			 lpBand->rcBand.right,
+			 rcBand.right,
 			 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE);
 	    }
 	}
@@ -1090,8 +874,8 @@ REBAR_CalcVertBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify)
 		xoff = REBAR_ALWAYS_SPACE;
 	    /* initialize Caption image rectangle  */
 	    SetRect (&lpBand->rcCapImage,
-		     lpBand->rcBand.left, lpBand->rcBand.top+xoff,
-		     lpBand->rcBand.right, lpBand->rcBand.top+xoff);
+                      rcBand.left, rcBand.top+xoff,
+                      rcBand.right, rcBand.top+xoff);
 	}
 
 	/* image is visible */
@@ -1103,8 +887,8 @@ REBAR_CalcVertBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify)
 
 	    /* set initial caption text rectangle */
 	    SetRect (&lpBand->rcCapText,
-		     lpBand->rcBand.left, lpBand->rcCapImage.bottom+REBAR_POST_IMAGE,
-		     lpBand->rcBand.right, lpBand->rcBand.top+lpBand->cxHeader);
+		     rcBand.left, lpBand->rcCapImage.bottom+REBAR_POST_IMAGE,
+		     rcBand.right, rcBand.top+lpBand->cxHeader);
 	    /* update band height *
 	       if (lpBand->uMinHeight < infoPtr->imageSize.cx + 2) {
 	       lpBand->uMinHeight = infoPtr->imageSize.cx + 2;
@@ -1114,8 +898,8 @@ REBAR_CalcVertBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify)
 	else {
 	    /* set initial caption text rectangle */
 	    SetRect (&lpBand->rcCapText,
-		     lpBand->rcBand.left, lpBand->rcCapImage.bottom,
-		     lpBand->rcBand.right, lpBand->rcBand.top+lpBand->cxHeader);
+		     rcBand.left, lpBand->rcCapImage.bottom,
+		     rcBand.right, rcBand.top+lpBand->cxHeader);
 	}
 
 	/* text is visible */
@@ -1126,40 +910,29 @@ REBAR_CalcVertBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify)
 	}
 
 	/* set initial child window rectangle if there is a child */
-	if (lpBand->fMask & RBBIM_CHILD) {
-	    yoff = lpBand->offChild.cx;
-	    xoff = lpBand->offChild.cy;
+	if (lpBand->hwndChild != NULL) {
+            int cxBand = rcBand.right - rcBand.left;
+            xoff = (cxBand - lpBand->cyChild) / 2;
 	    SetRect (&lpBand->rcChild,
-		     lpBand->rcBand.left+xoff, lpBand->rcBand.top+lpBand->cxHeader,
-		     lpBand->rcBand.right-xoff, lpBand->rcBand.bottom-yoff);
+		     rcBand.left + xoff,                   rcBand.top + lpBand->cxHeader,
+                     rcBand.left + xoff + lpBand->cyChild, rcBand.bottom - REBAR_POST_CHILD);
 	}
 	else {
 	    SetRect (&lpBand->rcChild,
-		     lpBand->rcBand.left, lpBand->rcBand.top+lpBand->cxHeader,
-		     lpBand->rcBand.right, lpBand->rcBand.bottom);
+		     rcBand.left, rcBand.top+lpBand->cxHeader,
+		     rcBand.right, rcBand.bottom);
 	}
 
-	/* flag if notify required and invalidate rectangle */
-	if (notify &&
-	    ((oldChild.right-oldChild.left != lpBand->rcChild.right-lpBand->rcChild.left) ||
-	     (oldChild.bottom-oldChild.top != lpBand->rcChild.bottom-lpBand->rcChild.top))) {
-	    TRACE("Child rectangle changed for band %u\n", i);
-            TRACE("    from (%d,%d)-(%d,%d)  to (%d,%d)-(%d,%d)\n",
-		  oldChild.left, oldChild.top,
-		  oldChild.right, oldChild.bottom,
-		  lpBand->rcChild.left, lpBand->rcChild.top,
-		  lpBand->rcChild.right, lpBand->rcChild.bottom);
-	}
 	if (lpBand->fDraw & NTF_INVALIDATE) {
             TRACE("invalidating (%d,%d)-(%d,%d)\n",
-		  lpBand->rcBand.left,
-		  lpBand->rcBand.top,
-		  lpBand->rcBand.right + ((lpBand->fDraw & DRAW_BOTTOMSEP) ? SEP_WIDTH_SIZE : 0),
-		  lpBand->rcBand.bottom + ((lpBand->fDraw & DRAW_RIGHTSEP) ? SEP_WIDTH_SIZE : 0));
+                  rcBand.left,
+                  rcBand.top,
+                  rcBand.right + SEP_WIDTH,
+                  rcBand.bottom + SEP_WIDTH);
 	    lpBand->fDraw &= ~NTF_INVALIDATE;
-	    work = lpBand->rcBand;
-	    if (lpBand->fDraw & DRAW_RIGHTSEP) work.bottom += SEP_WIDTH_SIZE;
-	    if (lpBand->fDraw & DRAW_BOTTOMSEP) work.right += SEP_WIDTH_SIZE;
+	    work = rcBand;
+	    work.bottom += SEP_WIDTH;
+	    work.right += SEP_WIDTH;
 	    InvalidateRect(infoPtr->hwndSelf, &work, TRUE);
 	}
 
@@ -1184,6 +957,9 @@ REBAR_ForceResize (REBAR_INFO *infoPtr)
 	   infoPtr->calcSize.cx, infoPtr->calcSize.cy,
 	   rc.right, rc.bottom);
 
+    if (infoPtr->dwStyle & CCS_NORESIZE)
+        return;
+
     /* If we need to shrink client, then skip size test */
     if ((infoPtr->calcSize.cy >= rc.bottom) &&
 	(infoPtr->calcSize.cx >= rc.right)) {
@@ -1236,12 +1012,12 @@ REBAR_ForceResize (REBAR_INFO *infoPtr)
 	    break;
 	case CCS_LEFT:
 	    /* _LEFT sets height to parents height */
-	    width += infoPtr->calcSize.cx;
+            width += infoPtr->calcSize.cx;
 	    height += (rcPcl.bottom - rcPcl.top);
 	    x += ((infoPtr->dwStyle & WS_BORDER) ? -xedge : 0);
 	    x += ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER);
 	    y += ((infoPtr->dwStyle & WS_BORDER) ? -yedge : 0);
-	    break;
+            break;
 	case CCS_RIGHT:
 	    /* FIXME: wrong wrong wrong */
 	    /* _RIGHT sets height to parents height */
@@ -1297,7 +1073,7 @@ REBAR_MoveChildWindows (REBAR_INFO *infoPtr, UINT start, UINT endplus)
 	    rbcz.uBand = i;
 	    rbcz.wID = lpBand->wID;
 	    rbcz.rcChild = lpBand->rcChild;
-	    rbcz.rcBand = lpBand->rcBand;
+            translate_rect(infoPtr, &rbcz.rcBand, &lpBand->rcBand);
 	    if (infoPtr->dwStyle & CCS_VERT)
 		rbcz.rcBand.top += lpBand->cxHeader;
 	    else
@@ -1311,7 +1087,7 @@ REBAR_MoveChildWindows (REBAR_INFO *infoPtr, UINT start, UINT endplus)
 		      rbcz.rcChild.left, rbcz.rcChild.top,
 		      rbcz.rcChild.right, rbcz.rcChild.bottom);
 		lpBand->rcChild = rbcz.rcChild;  /* *** ??? */
-	    }
+            }
 
 	    /* native (IE4 in "Favorites" frame **1) does:
 	     *   SetRect (&rc, -1, -1, -1, -1)
@@ -1394,552 +1170,312 @@ REBAR_MoveChildWindows (REBAR_INFO *infoPtr, UINT start, UINT endplus)
 
 }
 
-
-static VOID
-REBAR_Layout (REBAR_INFO *infoPtr, LPRECT lpRect, BOOL notify, BOOL resetclient)
-     /* Function: This routine is resposible for laying out all */
-     /*  the bands in a rebar. It assigns each band to a row and*/
-     /*  determines when to start a new row.                    */
+static void swap_size_if_vert(REBAR_INFO *infoPtr, SIZE *size)
 {
-    REBAR_BAND *lpBand, *prevBand;
-    RECT rcClient, rcAdj;
-    INT initx, inity, x, y, cx, cxsep, mmcy, mcy, clientcx, clientcy;
-    INT adjcx, adjcy, row, rightx, bottomy, origheight;
-    UINT i, j, rowstart, origrows, cntonrow;
-    BOOL dobreak;
-
-    if (!(infoPtr->fStatus & BAND_NEEDS_LAYOUT)) {
-	TRACE("no layout done. No band changed.\n");
-	REBAR_DumpBand (infoPtr);
-	return;
-    }
-    infoPtr->fStatus &= ~BAND_NEEDS_LAYOUT;
-    if (!infoPtr->DoRedraw) infoPtr->fStatus |= BAND_NEEDS_REDRAW;
-
-    GetClientRect (infoPtr->hwndSelf, &rcClient);
-    TRACE("Client is (%d,%d)-(%d,%d)\n",
-	  rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
-
-    if (lpRect) {
-	rcAdj = *lpRect;
-	TRACE("adjustment rect is (%d,%d)-(%d,%d)\n",
-	      rcAdj.left, rcAdj.top, rcAdj.right, rcAdj.bottom);
-    }
-    else {
-        CopyRect (&rcAdj, &rcClient);
-    }
-
-    clientcx = rcClient.right - rcClient.left;
-    clientcy = rcClient.bottom - rcClient.top;
-    adjcx = rcAdj.right - rcAdj.left;
-    adjcy = rcAdj.bottom - rcAdj.top;
-    if (resetclient) {
-        TRACE("window client rect will be set to adj rect\n");
-        clientcx = adjcx;
-        clientcy = adjcy;
-    }
-
-    if (!infoPtr->DoRedraw && (clientcx == 0) && (clientcy == 0)) {
-	ERR("no redraw and client is zero, skip layout\n");
-	infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
-	return;
-    }
-
-    /* save height of original control */
     if (infoPtr->dwStyle & CCS_VERT)
-        origheight = infoPtr->calcSize.cx;
-    else
-        origheight = infoPtr->calcSize.cy;
-    origrows = infoPtr->uNumRows;
-
-    initx = 0;
-    inity = 0;
-
-    /* ******* Start Phase 1 - all bands on row at minimum size ******* */
-
-    TRACE("band loop constants, clientcx=%d, clientcy=%d, adjcx=%d, adjcy=%d\n",
-	  clientcx, clientcy, adjcx, adjcy);
-    x = initx;
-    y = inity;
-    row = 0;
-    cx = 0;
-    mcy = 0;
-    rowstart = 0;
-    prevBand = NULL;
-    cntonrow = 0;
-
-    for (i = 0; i < infoPtr->uNumBands; i++) {
-	lpBand = &infoPtr->bands[i];
-	lpBand->fDraw = 0;
-	lpBand->iRow = row;
-
-	SetRectEmpty(&lpBand->rcChevron);
-
-	if (HIDDENBAND(lpBand)) continue;
-
-	lpBand->rcoldBand = lpBand->rcBand;
+    {
+        LONG tmp = size->cx;
+        size->cx = size->cy;
+        size->cy = tmp;
+    }
+}
 
-	/* Set the offset of the child window */
-	if ((lpBand->fMask & RBBIM_CHILD) &&
-	    !(lpBand->fStyle & RBBS_FIXEDSIZE)) {
-	    lpBand->offChild.cx = ((lpBand->fStyle & RBBS_CHILDEDGE) ? 4 : 0);
-	}
-	lpBand->offChild.cy = ((lpBand->fStyle & RBBS_CHILDEDGE) ? 2 : 0);
+static int next_band(REBAR_INFO *infoPtr, int i)
+{
+    int n;
+    for (n = i + 1; n < infoPtr->uNumBands; n++)
+        if (!HIDDENBAND(&infoPtr->bands[n]))
+            break;
+    return n;
+}
 
-	/* separator from previous band */
-	cxsep = (cntonrow == 0) ? 0 : SEP_WIDTH;
-	cx = lpBand->lcx;
+static int prev_band(REBAR_INFO *infoPtr, int i)
+{
+    int n;
+    for (n = i - 1; n >= 0; n--)
+        if (!HIDDENBAND(&infoPtr->bands[n]))
+            break;
+    return n;
+}
 
-        /* In native, 0 as one of the coordinates means no limit */
-	if (infoPtr->dwStyle & CCS_VERT)
-	    dobreak = (adjcy && (y + cx + cxsep > adjcy));
+static int get_row_begin_for_band(REBAR_INFO *infoPtr, INT iBand)
+{
+    int iLastBand = iBand;
+    int iRow = infoPtr->bands[iBand].iRow;
+    while ((iBand = prev_band(infoPtr, iBand)) >= 0) {
+        if (infoPtr->bands[iBand].iRow != iRow)
+            break;
         else
-	    dobreak = (adjcx && (x + cx + cxsep > adjcx));
-
-	/* This is the check for whether we need to start a new row */
-	if ( ( (lpBand->fStyle & RBBS_BREAK) && (i != 0) ) ||
-	     ( ((infoPtr->dwStyle & CCS_VERT) ? (y != 0) : (x != 0)) && dobreak)) {
-
-	    for (j = rowstart; j < i; j++) {
-		REBAR_BAND *lpB;
-		lpB = &infoPtr->bands[j];
-		if (infoPtr->dwStyle & CCS_VERT) {
-		    lpB->rcBand.right  = lpB->rcBand.left + mcy;
-		}
-		else {
-		    lpB->rcBand.bottom = lpB->rcBand.top + mcy;
-		}
-	    }
-
-	    TRACE("P1 Spliting to new row %d on band %u\n", row+1, i);
-	    if (infoPtr->dwStyle & CCS_VERT) {
-		y = inity;
-		x += (mcy + SEP_WIDTH);
-	    }
-	    else {
-		x = initx;
-		y += (mcy + SEP_WIDTH);
-	    }
-
-	    mcy = 0;
-	    cxsep = 0;
-	    row++;
-	    lpBand->iRow = row;
-	    prevBand = NULL;
-	    rowstart = i;
-	    cntonrow = 0;
-	}
-
-	if (mcy < lpBand->lcy + REBARSPACE(lpBand))
-	    mcy = lpBand->lcy + REBARSPACE(lpBand);
-
-	/* if boundary rect specified then limit mcy */
-	if (lpRect) {
-	    if (infoPtr->dwStyle & CCS_VERT) {
-	        if (adjcx && (x+mcy > adjcx)) {
-		    mcy = adjcx - x;
-		    TRACE("P1 row %u limiting mcy=%d, adjcx=%d, x=%d\n",
-			  i, mcy, adjcx, x);
-		}
-	    }
-	    else {
-	        if (adjcy && (y+mcy > adjcy)) {
-		    mcy = adjcy - y;
-		    TRACE("P1 row %u limiting mcy=%d, adjcy=%d, y=%d\n",
-			  i, mcy, adjcy, y);
-		}
-	    }
-	}
-
-	TRACE("P1 band %u, row %d, x=%d, y=%d, cxsep=%d, cx=%d\n",
-	      i, row,
-	      x, y, cxsep, cx);
-	if (infoPtr->dwStyle & CCS_VERT) {
-	    /* bound the bottom side if we have a bounding rectangle */
-	    rightx = clientcx;
-	    bottomy = (lpRect) ? min(clientcy, y+cxsep+cx) : y+cxsep+cx;
-	    lpBand->rcBand.left   = x;
-	    lpBand->rcBand.right  = x + min(mcy,
-					    lpBand->lcy+REBARSPACE(lpBand));
-	    lpBand->rcBand.top    = min(bottomy, y + cxsep);
-	    lpBand->rcBand.bottom = bottomy;
-	    lpBand->uMinHeight = lpBand->lcy;
-	    y = bottomy;
-	}
-	else {
-	    /* bound the right side if we have a bounding rectangle */
-	    rightx = (lpRect) ? min(clientcx, x+cxsep+cx) : x+cxsep+cx;
-	    bottomy = clientcy;
-	    lpBand->rcBand.left   = min(rightx, x + cxsep);
-	    lpBand->rcBand.right  = rightx;
-	    lpBand->rcBand.top    = y;
-	    lpBand->rcBand.bottom = y + min(mcy,
-					    lpBand->lcy+REBARSPACE(lpBand));
-	    lpBand->uMinHeight = lpBand->lcy;
-	    x = rightx;
-	}
-	TRACE("P1 band %u, row %d, (%d,%d)-(%d,%d)\n",
-	      i, row,
-	      lpBand->rcBand.left, lpBand->rcBand.top,
-	      lpBand->rcBand.right, lpBand->rcBand.bottom);
-	prevBand = lpBand;
-	cntonrow++;
+            iLastBand = iBand;
+    }
+    return iLastBand;
+}
 
-    } /* for (i = 0; i < infoPtr->uNumBands... */
+static int get_row_end_for_band(REBAR_INFO *infoPtr, INT iBand)
+{
+    int iRow = infoPtr->bands[iBand].iRow;
+    while ((iBand = next_band(infoPtr, iBand)) < infoPtr->uNumBands)
+        if (infoPtr->bands[iBand].iRow != iRow)
+            break;
+    return iBand;
+}
 
-    if (infoPtr->dwStyle & CCS_VERT)
-        x += mcy;
-    else
-        y += mcy;
+static void REBAR_SetRowRectsX(REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand)
+{
+    int xPos = 0, i;
+    for (i = iBeginBand; i < iEndBand; i = next_band(infoPtr, i))
+    {
+        REBAR_BAND *lpBand = &infoPtr->bands[i];
 
-    for (j = rowstart; j < infoPtr->uNumBands; j++) {
-	lpBand = &infoPtr->bands[j];
-	if (infoPtr->dwStyle & CCS_VERT) {
-	    lpBand->rcBand.right  = lpBand->rcBand.left + mcy;
-	}
-	else {
-	    lpBand->rcBand.bottom = lpBand->rcBand.top + mcy;
-	}
+        lpBand = &infoPtr->bands[i];
+        if (lpBand->rcBand.left != xPos || lpBand->rcBand.right != xPos + lpBand->cxEffective) {
+            lpBand->fDraw |= NTF_INVALIDATE;
+            TRACE("Setting rect %d to %d,%d\n", i, xPos, xPos + lpBand->cxEffective);
+            lpBand->rcBand.left = xPos;
+            lpBand->rcBand.right = xPos + lpBand->cxEffective;
+        }
+        xPos += lpBand->cxEffective + SEP_WIDTH;
     }
+}
 
-    if (infoPtr->uNumBands)
-        infoPtr->uNumRows = row + 1;
+static REBAR_BAND *REBAR_FindBandToGrow(REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand)
+{
+    INT iMaxLcx = 0, i;
 
-    /* ******* End Phase 1 - all bands on row at minimum size ******* */
+    for (i = iBeginBand; i < iEndBand; i = next_band(infoPtr, i))
+        iMaxLcx = max(iMaxLcx, infoPtr->bands[i].lcx);
 
+    for (i = prev_band(infoPtr, iEndBand); i >= iBeginBand; i = prev_band(infoPtr, i))
+        if (infoPtr->bands[i].cx > iMaxLcx)
+            break;
 
-    /* ******* Start Phase 1a - Adjust heights for RBS_VARHEIGHT off ******* */
+    if (i < iBeginBand)
+        for (i = prev_band(infoPtr, iEndBand); i >= iBeginBand; i = prev_band(infoPtr, i))
+            if (infoPtr->bands[i].lcx == iMaxLcx)
+                break;
 
-    mmcy = 0;
-    if (!(infoPtr->dwStyle & RBS_VARHEIGHT)) {
-	INT xy;
+    TRACE("Extra space for row [%d..%d) should be added to band %d\n", iBeginBand, iEndBand, i);
+    return &infoPtr->bands[i];
+}
 
-	/* get the max height of all bands */
-	for (i=0; i<infoPtr->uNumBands; i++) {
-	    lpBand = &infoPtr->bands[i];
-	    if (HIDDENBAND(lpBand)) continue;
-	    if (infoPtr->dwStyle & CCS_VERT)
-		mmcy = max(mmcy, lpBand->rcBand.right - lpBand->rcBand.left);
-	    else
-		mmcy = max(mmcy, lpBand->rcBand.bottom - lpBand->rcBand.top);
-	}
+static int REBAR_ShrinkBandsRTL(REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT cxShrink, BOOL bEnforce)
+{
+    REBAR_BAND *lpBand;
+    INT width, i;
 
-	/* now adjust all rectangles by using the height found above */
-	xy = 0;
-	row = 0;
-	for (i=0; i<infoPtr->uNumBands; i++) {
-	    lpBand = &infoPtr->bands[i];
-	    if (HIDDENBAND(lpBand)) continue;
-	    if (lpBand->iRow != row)
-		xy += (mmcy + SEP_WIDTH);
-	    if (infoPtr->dwStyle & CCS_VERT) {
-		lpBand->rcBand.left = xy;
-		lpBand->rcBand.right = xy + mmcy;
-	    }
-	    else {
-		lpBand->rcBand.top = xy;
-		lpBand->rcBand.bottom = xy + mmcy;
-	    }
-	}
+    TRACE("Shrinking bands [%d..%d) by %d, right-to-left\n", iBeginBand, iEndBand, cxShrink);
+    for (i = prev_band(infoPtr, iEndBand); i >= iBeginBand; i = prev_band(infoPtr, i))
+    {
+        lpBand = &infoPtr->bands[i];
 
-	/* set the x/y values to the correct maximum */
-	if (infoPtr->dwStyle & CCS_VERT)
-	    x = xy + mmcy;
-	else
-	    y = xy + mmcy;
+        width = max(lpBand->cxEffective - cxShrink, (int)lpBand->lcx);
+        cxShrink -= lpBand->cxEffective - width;
+        lpBand->cxEffective = width;
+        if (bEnforce)
+            lpBand->cx = lpBand->cxEffective;
+        if (cxShrink == 0)
+            break;
     }
-
-    /* ******* End Phase 1a - Adjust heights for RBS_VARHEIGHT off ******* */
+    return cxShrink;
+}
 
 
-    /* ******* Start Phase 2 - split rows till adjustment height full ******* */
+static int REBAR_ShrinkBandsLTR(REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT cxShrink, BOOL bEnforce)
+{
+    REBAR_BAND *lpBand;
+    INT width, i;
 
-    /* assumes that the following variables contain:                 */
-    /*   y/x       current height/width of all rows                  */
-    /* adjcy/adjcx adjustment height/width or 0 (as small as possible) */
-    if (lpRect && ((infoPtr->dwStyle & CCS_VERT) ? adjcx : adjcy)) {
-        INT i, prev_rh, new_rh, adj_rh, prev_idx, current_idx;
-	REBAR_BAND *prev, *current, *walk;
-	UINT j;
+    TRACE("Shrinking bands [%d..%d) by %d, left-to-right\n", iBeginBand, iEndBand, cxShrink);
+    for (i = iBeginBand; i < iEndBand; i = next_band(infoPtr, i))
+    {
+        lpBand = &infoPtr->bands[i];
 
-/* FIXME:  problem # 2 */
-	if (((infoPtr->dwStyle & CCS_VERT) ?
-#if PROBLEM2
-	     (x < adjcx) : (y < adjcy)
-#else
-	     (adjcx - x > 5) : (adjcy - y > 4)
-#endif
-	     ) &&
-	    (infoPtr->uNumBands > 1)) {
-	    for (i=(INT)infoPtr->uNumBands-2; i>=0; i--) {
-		TRACE("P2 adjcx=%d, adjcy=%d, x=%d, y=%d\n",
-		      adjcx, adjcy, x, y);
-
-		/* find the current band (starts at i+1) */
-		current = &infoPtr->bands[i+1];
-		current_idx = i+1;
-		while (HIDDENBAND(current)) {
-		    i--;
-		    if (i < 0) break; /* out of bands */
-		    current = &infoPtr->bands[i+1];
-		    current_idx = i+1;
-		}
-		if (i < 0) break; /* out of bands */
-
-		/* now find the prev band (starts at i) */
-	        prev = &infoPtr->bands[i];
-		prev_idx = i;
-		while (HIDDENBAND(prev)) {
-		    i--;
-		    if (i < 0) break; /* out of bands */
-		    prev = &infoPtr->bands[i];
-		    prev_idx = i;
-		}
-		if (i < 0) break; /* out of bands */
-
-		prev_rh = ircBw(prev);
-		if (prev->iRow == current->iRow) {
-		    new_rh = (infoPtr->dwStyle & RBS_VARHEIGHT) ?
-			current->lcy + REBARSPACE(current) :
-			mmcy;
-		    adj_rh = new_rh + SEP_WIDTH;
-		    infoPtr->uNumRows++;
-		    current->fDraw |= NTF_INVALIDATE;
-		    current->iRow++;
-		    if (infoPtr->dwStyle & CCS_VERT) {
-		        current->rcBand.top = inity;
-			current->rcBand.bottom = clientcy;
-			current->rcBand.left += (prev_rh + SEP_WIDTH);
-			current->rcBand.right = current->rcBand.left + new_rh;
-			x += adj_rh;
-		    }
-		    else {
-		        current->rcBand.left = initx;
-			current->rcBand.right = clientcx;
-			current->rcBand.top += (prev_rh + SEP_WIDTH);
-			current->rcBand.bottom = current->rcBand.top + new_rh;
-			y += adj_rh;
-		    }
-                    TRACE("P2 moving band %d to own row at (%d,%d)-(%d,%d)\n",
-			  current_idx,
-			  current->rcBand.left, current->rcBand.top,
-			  current->rcBand.right, current->rcBand.bottom);
-                    TRACE("P2 prev band %d at (%d,%d)-(%d,%d)\n",
-			  prev_idx,
-			  prev->rcBand.left, prev->rcBand.top,
-			  prev->rcBand.right, prev->rcBand.bottom);
-		    TRACE("P2 values: prev_rh=%d, new_rh=%d, adj_rh=%d\n",
-			  prev_rh, new_rh, adj_rh);
-		    /* for bands below current adjust row # and top/bottom */
-		    for (j = current_idx+1; j<infoPtr->uNumBands; j++) {
-		        walk = &infoPtr->bands[j];
-			if (HIDDENBAND(walk)) continue;
-			walk->fDraw |= NTF_INVALIDATE;
-			walk->iRow++;
-			if (infoPtr->dwStyle & CCS_VERT) {
-			    walk->rcBand.left += adj_rh;
-			    walk->rcBand.right += adj_rh;
-			}
-			else {
-			    walk->rcBand.top += adj_rh;
-			    walk->rcBand.bottom += adj_rh;
-			}
-		    }
-		    if ((infoPtr->dwStyle & CCS_VERT) ? (x >= adjcx) : (y >= adjcy))
-		        break; /* all done */
-		}
-	    }
-	}
+        width = max(lpBand->cxEffective - cxShrink, (int)lpBand->lcx);
+        cxShrink -= lpBand->cxEffective - width;
+        lpBand->cxEffective = width;
+        if (bEnforce)
+            lpBand->cx = lpBand->cxEffective;
+        if (cxShrink == 0)
+            break;
     }
+    return cxShrink;
+}
 
-    /* ******* End Phase 2 - split rows till adjustment height full ******* */
-
-
-    /* ******* Start Phase 2a - mark first and last band in each ******* */
+static int REBAR_SetBandsHeight(REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT yStart)
+{
+    REBAR_BAND *lpBand;
+    int yMaxHeight = 0;
+    int yPos = yStart;
+    int row = infoPtr->bands[iBeginBand].iRow;
+    int i;
+    for (i = iBeginBand; i < iEndBand; i = next_band(infoPtr, i))
+    {
+        lpBand = &infoPtr->bands[i];
+        yMaxHeight = max(yMaxHeight, lpBand->lcy);
+    }
+    TRACE("Bands [%d; %d) height: %d\n", iBeginBand, iEndBand, yMaxHeight);
 
-    prevBand = NULL;
-    for (i = 0; i < infoPtr->uNumBands; i++) { 	 
-        lpBand = &infoPtr->bands[i]; 	 
-        if (HIDDENBAND(lpBand))
-            continue;
-        if( !prevBand ) {
-            lpBand->fDraw |= DRAW_FIRST_IN_ROW;
-            prevBand = lpBand;
+    for (i = iBeginBand; i < iEndBand; i = next_band(infoPtr, i))
+    {
+        lpBand = &infoPtr->bands[i];
+        /* we may be called for multiple rows if RBS_VARHEIGHT not set */
+        if (lpBand->iRow != row) {
+            yPos += yMaxHeight + SEP_WIDTH;
+            row = lpBand->iRow;
         }
-        else if( prevBand->iRow == lpBand->iRow )
-            prevBand = lpBand;
-        else {
-            prevBand->fDraw |= DRAW_LAST_IN_ROW;
-            lpBand->fDraw |= DRAW_FIRST_IN_ROW;
-            prevBand = lpBand;
+
+        if (lpBand->rcBand.top != yPos || lpBand->rcBand.bottom != yPos + yMaxHeight) {
+            lpBand->fDraw |= NTF_INVALIDATE;
+            lpBand->rcBand.top = yPos;
+            lpBand->rcBand.bottom = yPos + yMaxHeight;
+            TRACE("Band %d: %s\n", i, wine_dbgstr_rect(&lpBand->rcBand));
         }
     }
-    if( prevBand )
-        prevBand->fDraw |= DRAW_LAST_IN_ROW;
-
-    /* ******* End Phase 2a - mark first and last band in each ******* */
-
-
-    /* ******* Start Phase 2b - adjust all bands for height full ******* */
-    /* assumes that the following variables contain:                 */
-    /*   y/x     current height/width of all rows                    */
-    /*   clientcy/clientcx     height/width of client area           */
+    return yPos + yMaxHeight;
+}
 
-    if (((infoPtr->dwStyle & CCS_VERT) ? clientcx > x : clientcy > y) &&
-	infoPtr->uNumBands) {
-	INT diff, i;
-	UINT j;
+static void REBAR_LayoutRow(REBAR_INFO *infoPtr, int iBeginBand, int iEndBand, int cx, int *piRow, int *pyPos)
+{
+    REBAR_BAND *lpBand;
+    int i, extra;
+    int width = 0;
 
-	diff = (infoPtr->dwStyle & CCS_VERT) ? clientcx - x : clientcy - y;
+    TRACE("Adjusting row [%d;%d). Width: %d\n", iBeginBand, iEndBand, cx);
+    for (i = iBeginBand; i < iEndBand; i++)
+        infoPtr->bands[i].iRow = *piRow;
 
-        /* iterate backwards thru the rows */
-        for (i = infoPtr->uNumBands-1; i>=0; i--) {
-	    lpBand = &infoPtr->bands[i];
-	    if(HIDDENBAND(lpBand)) continue;
-
-	    /* if row has more than 1 band, ignore it */
-            if( !(lpBand->fDraw&DRAW_FIRST_IN_ROW) )
-                continue;
-            if( !(lpBand->fDraw&DRAW_LAST_IN_ROW) )
-                continue;
-
-            /* FIXME: this next line is wrong, but fixing it to be inverted causes IE's sidebars to be the wrong size */
-	    if (lpBand->fMask & RBBS_VARIABLEHEIGHT) continue;
-	    if (((INT)lpBand->cyMaxChild < 1) ||
-		((INT)lpBand->cyIntegral < 1)) {
-		if (lpBand->cyMaxChild + lpBand->cyIntegral == 0) continue;
-		ERR("P2b band %u RBBS_VARIABLEHEIGHT set but cyMax=%d, cyInt=%d\n",
-		    i, lpBand->cyMaxChild, lpBand->cyIntegral);
-		continue;
-	    }
-	    /* j is now the maximum height/width in the client area */
-	    j = ((diff / lpBand->cyIntegral) * lpBand->cyIntegral) +
-		ircBw(lpBand);
-	    if (j > lpBand->cyMaxChild + REBARSPACE(lpBand))
-		j = lpBand->cyMaxChild + REBARSPACE(lpBand);
-	    diff -= (j - ircBw(lpBand));
-	    if (infoPtr->dwStyle & CCS_VERT)
-		lpBand->rcBand.right = lpBand->rcBand.left + j;
-	    else
-		lpBand->rcBand.bottom = lpBand->rcBand.top + j;
-            TRACE("P2b band %d, row %d changed to (%d,%d)-(%d,%d)\n",
-		  i, lpBand->iRow,
-		  lpBand->rcBand.left, lpBand->rcBand.top,
-		  lpBand->rcBand.right, lpBand->rcBand.bottom);
-	    if (diff <= 0) break;
-	}
-	if (diff < 0) {
-	    ERR("P2b allocated more than available, diff=%d\n", diff);
-	    diff = 0;
-	}
-	if (infoPtr->dwStyle & CCS_VERT)
-	    x = clientcx - diff;
-	else
-	    y = clientcy - diff;
+    /* compute the extra space */
+    for (i = iBeginBand; i < iEndBand; i = next_band(infoPtr, i))
+    {
+        lpBand = &infoPtr->bands[i];
+        if (i > iBeginBand)
+            width += SEP_WIDTH;
+        lpBand->cxEffective = max(lpBand->lcx, lpBand->cx);
+        width += lpBand->cxEffective;
+    }
+
+    extra = cx - width;
+    TRACE("Extra space: %d\n", extra);
+    if (extra < 0) {
+        int ret = REBAR_ShrinkBandsRTL(infoPtr, iBeginBand, iEndBand, -extra, FALSE);
+        if (ret > 0 && next_band(infoPtr, iBeginBand) != iEndBand)  /* one band may be longer than expected... */
+            ERR("Error layouting row %d - couldn't shrink for %d pixels (%d total shrink)\n", *piRow, ret, -extra);
+    } else
+    if (extra > 0) {
+        lpBand = REBAR_FindBandToGrow(infoPtr, iBeginBand, iEndBand);
+        lpBand->cxEffective += extra;
+    }
+
+    REBAR_SetRowRectsX(infoPtr, iBeginBand, iEndBand);
+    if (infoPtr->dwStyle & RBS_VARHEIGHT)
+    {
+        if (*piRow > 0)
+            *pyPos += SEP_WIDTH;
+        *pyPos = REBAR_SetBandsHeight(infoPtr, iBeginBand, iEndBand, *pyPos);
     }
+    (*piRow)++;
+}
 
-    /* ******* End Phase 2b - adjust all bands for height full ******* */
-
-
-    /* ******* Start Phase 3 - adjust all bands for width full ******* */
-
-    if (infoPtr->uNumBands) {
-        int startband;
-
-	/* If RBS_BANDBORDERS set then indicate to draw bottom separator */
-	/* on all bands in all rows but last row.                        */
-	/* Also indicate to draw the right separator for each band in    */
-	/* each row but the rightmost band.                              */
-	if (infoPtr->dwStyle & RBS_BANDBORDERS) {
-
-            for (i=0; i<infoPtr->uNumBands; i++) {
-	        lpBand = &infoPtr->bands[i];
-		if (HIDDENBAND(lpBand))
-                    continue;
+static VOID
+REBAR_Layout(REBAR_INFO *infoPtr, LPRECT lpRect, BOOL notify)
+{
+    REBAR_BAND *lpBand;
+    RECT rcAdj;
+    INT adjcx, adjcy, i;
+    INT rowstart = 0;
+    INT row = 0;
+    INT xMin, yPos;
+    INT cyTarget;
+    const INT yInit = 0;
 
-                /* not righthand bands */
-                if( !(lpBand->fDraw & DRAW_LAST_IN_ROW) )
-		    lpBand->fDraw |= DRAW_RIGHTSEP;
+    if (!(infoPtr->fStatus & BAND_NEEDS_LAYOUT)) {
+	TRACE("no layout done. No band changed.\n");
+	REBAR_DumpBand (infoPtr);
+	return;
+    }
 
-                /* not the last row */
-                if( lpBand->iRow != infoPtr->uNumRows )
-		    lpBand->fDraw |= DRAW_BOTTOMSEP;
-	    }
-	}
+    infoPtr->fStatus &= ~BAND_NEEDS_LAYOUT;
+    if (!infoPtr->DoRedraw) infoPtr->fStatus |= BAND_NEEDS_REDRAW;
 
-	/* Distribute the extra space on the horizontal and adjust  */
-	/* all bands in row to same height.                         */
-	mcy = 0;
-        startband = -1;
-        for (i=0; i<infoPtr->uNumBands; i++) {
+    cyTarget = 0;
+    if (lpRect) {
+        rcAdj = *lpRect;
+        cyTarget = get_rect_cy(infoPtr, lpRect);
+    } else if (infoPtr->dwStyle & CCS_NORESIZE || GetParent(infoPtr->hwndSelf) == NULL)
+        GetClientRect(infoPtr->hwndSelf, &rcAdj);
+    else
+        GetClientRect(GetParent(infoPtr->hwndSelf), &rcAdj);
+    TRACE("adjustment rect is (%d,%d)-(%d,%d)\n", rcAdj.left, rcAdj.top, rcAdj.right, rcAdj.bottom);
 
-            lpBand = &infoPtr->bands[i];
+    adjcx = get_rect_cx(infoPtr, &rcAdj);
+    adjcy = get_rect_cy(infoPtr, &rcAdj);
 
-            if( lpBand->fDraw & DRAW_FIRST_IN_ROW )
-            {
-                startband = i;
-                mcy = 0;
-            }
+    if (infoPtr->uNumBands == 0) {
+        TRACE("No bands - setting size to (0,%d), vert: %lx\n", adjcx, infoPtr->dwStyle & CCS_VERT);
+        infoPtr->oldSize = infoPtr->calcSize;
+        infoPtr->calcSize.cx = adjcx;
+        infoPtr->calcSize.cy = 0;
+        swap_size_if_vert(infoPtr, &infoPtr->calcSize);
+        infoPtr->uNumRows = 0;
+        REBAR_ForceResize(infoPtr);
+        return;
+    }
 
-            if ( (mcy < ircBw(lpBand)) && !HIDDENBAND(lpBand) )
-                mcy = ircBw(lpBand);
+/*    if (!infoPtr->DoRedraw && (clientcx == 0) && (clientcy == 0)) {
+	ERR("no redraw and client is zero, skip layout\n");
+	infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
+	return;
+    }*/
 
-            if( lpBand->fDraw & DRAW_LAST_IN_ROW )
-            {
-	        TRACE("P3 processing row %d, starting band %d, ending band %d\n",
-		      lpBand->iRow, startband, i);
-                if( startband < 0 )
-                    ERR("Last band %d with no first, row %d\n", i, lpBand->iRow);
-
-	        REBAR_AdjustBands (infoPtr, startband, i,
-			       (infoPtr->dwStyle & CCS_VERT) ?
-			       clientcy : clientcx, mcy);
-            }
-	}
+    yPos = yInit;
+    xMin = 0;
+    /* divide rows */
+    i = 0;
+    for (i = 0; i < infoPtr->uNumBands; i++)
+    {
+        lpBand = &infoPtr->bands[i];
+        if (HIDDENBAND(lpBand)) continue;
+        lpBand->rcoldBand = lpBand->rcBand;
+
+        if (i > rowstart && (lpBand->fStyle & RBBS_BREAK || xMin + lpBand->lcx > adjcx)) {
+            TRACE("%s break on band %d\n", (lpBand->fStyle & RBBS_BREAK ? "Hard" : "Soft"), i - 1);
+            REBAR_LayoutRow(infoPtr, rowstart, i, adjcx, &row, &yPos);
+            rowstart = i;
+            xMin = 0;
+        }
+        else
+            xMin += SEP_WIDTH;
 
-	/* Calculate the other rectangles in each band */
-	if (infoPtr->dwStyle & CCS_VERT) {
-	    REBAR_CalcVertBand (infoPtr, 0, infoPtr->uNumBands,
-				notify);
-	}
-	else {
-	    REBAR_CalcHorzBand (infoPtr, 0, infoPtr->uNumBands,
-				notify);
-	}
+        xMin += lpBand->lcx;
     }
+    REBAR_LayoutRow(infoPtr, rowstart, infoPtr->uNumBands, adjcx, &row, &yPos);
+
+    if (!(infoPtr->dwStyle & RBS_VARHEIGHT))
+        yPos = REBAR_SetBandsHeight(infoPtr, 0, infoPtr->uNumBands, yInit);
 
-    /* ******* End Phase 3 - adjust all bands for width full ******* */
+    infoPtr->uNumRows = row;
 
+    if (infoPtr->dwStyle & CCS_VERT)
+        REBAR_CalcVertBand(infoPtr, 0, infoPtr->uNumBands);
+    else
+        REBAR_CalcHorzBand(infoPtr, 0, infoPtr->uNumBands);
     /* now compute size of Rebar itself */
     infoPtr->oldSize = infoPtr->calcSize;
-    if (infoPtr->uNumBands == 0) {
-	/* we have no bands, so make size the size of client */
-	x = clientcx;
-	y = clientcy;
-    }
-    if (infoPtr->dwStyle & CCS_VERT) {
-        if( infoPtr->uNumBands != 0 && x < REBAR_MINSIZE )
-            x = REBAR_MINSIZE;
-	infoPtr->calcSize.cx = x;
-	infoPtr->calcSize.cy = clientcy;
-	TRACE("vert, notify=%d, x=%d, origheight=%d\n",
-	      notify, x, origheight);
-	if (notify && (x != origheight)) infoPtr->fStatus |= NTF_HGHTCHG;
-    }
-    else {
-        if( infoPtr->uNumBands != 0 && y < REBAR_MINSIZE )
-            y = REBAR_MINSIZE;
-	infoPtr->calcSize.cx = clientcx;
-	infoPtr->calcSize.cy = y;
-	TRACE("horz, notify=%d, y=%d, origheight=%d\n",
-	      notify, y, origheight);
-	if (notify && (y != origheight)) infoPtr->fStatus |= NTF_HGHTCHG;
-    }
 
-    REBAR_DumpBand (infoPtr);
+/*    if (yPos < REBAR_MINSIZE)
+    yPos = REBAR_MINSIZE;*/
+    infoPtr->calcSize.cx = adjcx;
+    infoPtr->calcSize.cy = yPos;
+    swap_size_if_vert(infoPtr, &infoPtr->calcSize);
+    if (infoPtr->calcSize.cx != infoPtr->oldSize.cx || infoPtr->calcSize.cy != infoPtr->oldSize.cy)
+        if (notify && (yPos != infoPtr->calcSize.cy)) infoPtr->fStatus |= NTF_HGHTCHG;
 
-    REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands);
+    TRACE("calcsize notify=%d, size=(%d, %d), origheight=(%d,%d)\n", notify,
+            infoPtr->calcSize.cx, infoPtr->calcSize.cy,
+	    infoPtr->oldSize.cx, infoPtr->oldSize.cy);
 
+    REBAR_DumpBand (infoPtr);
+    REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands);
     REBAR_ForceResize (infoPtr);
 }
 
@@ -1958,10 +1494,6 @@ REBAR_ValidateBand (REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
     lpBand->fStatus = 0;
     lpBand->lcx = 0;
     lpBand->lcy = 0;
-    lpBand->ccx = 0;
-    lpBand->ccy = 0;
-    lpBand->hcx = 0;
-    lpBand->hcy = 0;
 
     /* Data coming in from users into the cx... and cy... fields   */
     /* may be bad, just garbage, because the user never clears     */
@@ -1977,7 +1509,6 @@ REBAR_ValidateBand (REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
     if (lpBand->cyMinChild > 65535) lpBand->cyMinChild = 0;
     if (lpBand->cx         > 65535) lpBand->cx         = 0;
     if (lpBand->cyChild    > 65535) lpBand->cyChild    = 0;
-    if (lpBand->cyMaxChild > 65535) lpBand->cyMaxChild = 0;
     if (lpBand->cyIntegral > 65535) lpBand->cyIntegral = 0;
     if (lpBand->cxIdeal    > 65535) lpBand->cxIdeal    = 0;
     if (lpBand->cxHeader   > 65535) lpBand->cxHeader   = 0;
@@ -2057,38 +1588,18 @@ REBAR_ValidateBand (REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
 
 
     /* Now compute minimum size of child window */
-    lpBand->offChild.cx = 0;
-    lpBand->offChild.cy = 0;
     lpBand->lcy = textheight;
-    lpBand->ccy = lpBand->lcy;
-    if (lpBand->fMask & RBBIM_CHILDSIZE) {
-        lpBand->lcx = lpBand->cxMinChild;
-
+    if (lpBand->hwndChild != NULL) {
 	/* Set the .cy values for CHILDSIZE case */
-        lpBand->lcy = max(lpBand->lcy, lpBand->cyMinChild);
-	lpBand->ccy = lpBand->lcy;
-        lpBand->hcy = lpBand->lcy;
-        if (lpBand->cyMaxChild != 0xffffffff) {
-	    lpBand->hcy = lpBand->cyMaxChild;
-        }
-	if (lpBand->cyChild != 0xffffffff)
-	    lpBand->ccy = max (lpBand->cyChild, lpBand->lcy);
-
+        lpBand->lcy = max(lpBand->lcy, lpBand->cyChild + REBARSPACE(lpBand));
         TRACE("_CHILDSIZE\n");
     }
-    if (lpBand->fMask & RBBIM_SIZE) {
-        lpBand->hcx = max (lpBand->cx-lpBand->cxHeader, lpBand->lcx);
-        TRACE("_SIZE\n");
-    }
     else
-        lpBand->hcx = lpBand->lcx;
-    lpBand->ccx = lpBand->hcx;
-
-    /* make ->.cx include header size for _Layout */
-    lpBand->lcx += lpBand->cxHeader;
-    lpBand->ccx += lpBand->cxHeader;
-    lpBand->hcx += lpBand->cxHeader;
+        lpBand->lcy = max(lpBand->lcy, REBAR_NO_CHILD_HEIGHT);
 
+    lpBand->lcx = lpBand->cxMinChild + lpBand->cxHeader + REBAR_POST_CHILD;
+    if (lpBand->fStyle & RBBS_USECHEVRON && lpBand->cxMinChild < lpBand->cxIdeal)
+        lpBand->lcx += CHEVRON_WIDTH;
 }
 
 static BOOL
@@ -2158,15 +1669,17 @@ REBAR_CommonSetupBand(HWND hwnd, LPREBARBANDINFOW lprbbi, REBAR_BAND *lpBand)
     {
 	lpBand->cxMinChild = lprbbi->cxMinChild;
 	lpBand->cyMinChild = lprbbi->cyMinChild;
-	if (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) {
-	    lpBand->cyChild    = lprbbi->cyChild;
+        /* These fields where added in WIN32_IE == 0x400 and are set only for RBBS_VARIABLEHEIGHT bands */
+        if (lprbbi->cbSize >= sizeof (REBARBANDINFOA) && (lprbbi->fStyle & RBBS_VARIABLEHEIGHT)) {
 	    lpBand->cyMaxChild = lprbbi->cyMaxChild;
-	    lpBand->cyIntegral = lprbbi->cyIntegral;
-	}
-	else { /* special case - these should be zeroed out since   */
-	       /* RBBIM_CHILDSIZE added these in WIN32_IE >= 0x0400 */
-	    lpBand->cyChild    = 0;
-	    lpBand->cyMaxChild = 0;
+            lpBand->cyIntegral = lprbbi->cyIntegral;
+
+            lpBand->cyChild = lpBand->cyMinChild;
+            round_child_height(lpBand, lprbbi->cyChild);  /* try to increase cyChild */
+        }
+	else {
+	    lpBand->cyChild    = lpBand->cyMinChild;
+	    lpBand->cyMaxChild = 0x7fffffff;
 	    lpBand->cyIntegral = 0;
 	}
         bChanged = TRUE;
@@ -2232,7 +1745,7 @@ REBAR_InternalEraseBkGnd (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam, REC
     UINT i;
     INT oldrow;
     HDC hdc = (HDC)wParam;
-    RECT rect, cr;
+    RECT cr;
     COLORREF old = CLR_NONE, new;
     HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
 
@@ -2240,15 +1753,17 @@ REBAR_InternalEraseBkGnd (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam, REC
 
     oldrow = -1;
     for(i=0; i<infoPtr->uNumBands; i++) {
+        RECT rcBand;
         lpBand = &infoPtr->bands[i];
 	if (HIDDENBAND(lpBand)) continue;
+        translate_rect(infoPtr, &rcBand, &lpBand->rcBand);
 
 	/* draw band separator between rows */
 	if (lpBand->iRow != oldrow) {
 	    oldrow = lpBand->iRow;
-	    if (lpBand->fDraw & DRAW_BOTTOMSEP) {
+	    if (infoPtr->dwStyle & RBS_BANDBORDERS) {
 		RECT rcRowSep;
-		rcRowSep = lpBand->rcBand;
+		rcRowSep = rcBand;
 		if (infoPtr->dwStyle & CCS_VERT) {
 		    rcRowSep.right += SEP_WIDTH_SIZE;
 		    rcRowSep.bottom = infoPtr->calcSize.cy;
@@ -2272,18 +1787,20 @@ REBAR_InternalEraseBkGnd (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam, REC
 	}
 
 	/* draw band separator between bands in a row */
-	if (lpBand->fDraw & DRAW_RIGHTSEP) {
+        if (infoPtr->dwStyle & RBS_BANDBORDERS && lpBand->rcBand.left > 0) {
 	    RECT rcSep;
-	    rcSep = lpBand->rcBand;
+	    rcSep = rcBand;
 	    if (infoPtr->dwStyle & CCS_VERT) {
-		rcSep.bottom += SEP_WIDTH_SIZE;
+                rcSep.bottom = rcSep.top;
+		rcSep.top -= SEP_WIDTH_SIZE;
                 if (theme)
                     DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcSep, EDGE_ETCHED, BF_BOTTOM, NULL);
                 else
 		    DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_BOTTOM);
 	    }
 	    else {
-		rcSep.right += SEP_WIDTH_SIZE;
+                rcSep.right = rcSep.left;
+		rcSep.left -= SEP_WIDTH_SIZE;
                 if (theme)
                     DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcSep, EDGE_ETCHED, BF_RIGHT, NULL);
                 else
@@ -2314,13 +1831,11 @@ REBAR_InternalEraseBkGnd (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam, REC
 #endif
 	}
 
-	rect = lpBand->rcBand;
-
         if (theme)
         {
             /* When themed, the background color is ignored (but not a 
              * background bitmap */
-            DrawThemeBackground (theme, hdc, 0, 0, &cr, &rect);
+            DrawThemeBackground (theme, hdc, 0, 0, &cr, &rcBand);
         }
         else
         {
@@ -2329,11 +1844,11 @@ REBAR_InternalEraseBkGnd (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam, REC
                   (lpBand->clrBack == CLR_NONE) ? "none" :
                     ((lpBand->clrBack == CLR_DEFAULT) ? "dft" : ""),
                   GetBkColor(hdc),
-                  lpBand->rcBand.left,lpBand->rcBand.top,
-                  lpBand->rcBand.right,lpBand->rcBand.bottom,
+                  rcBand.left,rcBand.top,
+                  rcBand.right,rcBand.bottom,
                   clip->left, clip->top,
                   clip->right, clip->bottom);
-            ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, 0);
+            ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &rcBand, NULL, 0, 0);
             if (lpBand->clrBack != CLR_NONE)
                 SetBkColor (hdc, old);
         }
@@ -2363,9 +1878,11 @@ REBAR_InternalHitTest (REBAR_INFO *infoPtr, const LPPOINT lpPt, UINT *pFlags, IN
 	else {
 	    /* somewhere inside */
 	    for (iCount = 0; iCount < infoPtr->uNumBands; iCount++) {
+                RECT rcBand;
 		lpBand = &infoPtr->bands[iCount];
-		if (HIDDENBAND(lpBand)) continue;
-		if (PtInRect (&lpBand->rcBand, *lpPt)) {
+                translate_rect(infoPtr, &rcBand, &lpBand->rcBand);
+                if (HIDDENBAND(lpBand)) continue;
+		if (PtInRect (&rcBand, *lpPt)) {
 		    if (pBand)
 			*pBand = iCount;
 		    if (PtInRect (&lpBand->rcGripper, *lpPt)) {
@@ -2418,76 +1935,6 @@ REBAR_InternalHitTest (REBAR_INFO *infoPtr, const LPPOINT lpPt, UINT *pFlags, IN
     }
 }
 
-
-static INT
-REBAR_Shrink (REBAR_INFO *infoPtr, REBAR_BAND *band, INT movement, INT i)
-     /* Function:  This attempts to shrink the given band by the  */
-     /*  the amount in "movement". A shrink to the left is indi-  */
-     /*  cated by "movement" being negative. "i" is merely the    */
-     /*  band index for trace messages.                           */
-{
-    INT Leadjust, Readjust, avail, ret;
-
-    /* Note: a left drag is indicated by "movement" being negative.  */
-    /*       Similarly, a right drag is indicated by "movement"      */
-    /*       being positive. "movement" should never be 0, but if    */
-    /*       it is then the band does not move.                      */
-
-    avail = rcBw(band) - band->lcx;
-
-    /* now compute the Left End adjustment factor and Right End */
-    /* adjustment factor. They may be different if shrinking.   */
-    if (avail <= 0) {
-        /* if this band is not shrinkable, then just move it */
-        Leadjust = Readjust = movement;
-	ret = movement;
-    }
-    else {
-        if (movement < 0) {
-	    /* Drag to left */
-	    if (avail <= abs(movement)) {
-	        Readjust = movement;
-		Leadjust = movement + avail;
-		ret = Leadjust;
-	    }
-	    else {
-	        Readjust = movement;
-		Leadjust = 0;
-		ret = 0;
-	    }
-	}
-	else {
-	    /* Drag to right */
-	    if (avail <= abs(movement)) {
-	        Leadjust = movement;
-		Readjust = movement - avail;
-		ret = Readjust;
-	    }
-	    else {
-	        Leadjust = movement;
-		Readjust = 0;
-		ret = 0;
-	    }
-	}
-    }
-
-    /* Reasonability Check */
-    if (rcBlt(band) + Leadjust < 0) {
-        ERR("adjustment will fail, band %d: left=%d, right=%d, move=%d, rtn=%d\n",
-	    i, Leadjust, Readjust, movement, ret);
-    }
-
-    LEADJ(band, Leadjust);
-    READJ(band, Readjust);
-
-    TRACE("band %d:  left=%d, right=%d, move=%d, rtn=%d, rcBand=(%d,%d)-(%d,%d)\n",
-	  i, Leadjust, Readjust, movement, ret,
-	  band->rcBand.left, band->rcBand.top,
-	  band->rcBand.right, band->rcBand.bottom);
-    return ret;
-}
-
-
 static void
 REBAR_HandleLRDrag (REBAR_INFO *infoPtr, const POINT *ptsmove)
      /* Function:  This will implement the functionality of a     */
@@ -2497,14 +1944,11 @@ REBAR_HandleLRDrag (REBAR_INFO *infoPtr, const POINT *ptsmove)
      /*  **** FIXME Switching order of bands in a row not   ****  */
      /*  ****       yet implemented.                        ****  */
 {
-    REBAR_BAND *hitBand, *band, *mindBand, *maxdBand;
-    RECT newrect;
-    INT imindBand = -1, imaxdBand, ihitBand, i, movement;
-    INT RHeaderSum = 0, LHeaderSum = 0;
-    INT compress;
+    REBAR_BAND *hitBand;
+    INT iHitBand, iRowBegin, iRowEnd;
+    INT movement, xBand;
 
     /* on first significant mouse movement, issue notify */
-
     if (!(infoPtr->fStatus & BEGIN_DRAG_ISSUED)) {
 	if (REBAR_Notify_NMREBAR (infoPtr, -1, RBN_BEGINDRAG)) {
 	    /* Notify returned TRUE - abort drag */
@@ -2518,126 +1962,32 @@ REBAR_HandleLRDrag (REBAR_INFO *infoPtr, const POINT *ptsmove)
 	infoPtr->fStatus |= BEGIN_DRAG_ISSUED;
     }
 
-    ihitBand = infoPtr->iGrabbedBand;
-    hitBand = &infoPtr->bands[ihitBand];
-    imaxdBand = ihitBand; /* to suppress warning message */
+    iHitBand = infoPtr->iGrabbedBand;
+    iRowBegin = get_row_begin_for_band(infoPtr, iHitBand);
+    iRowEnd = get_row_end_for_band(infoPtr, iHitBand);
+    hitBand = &infoPtr->bands[iHitBand];
 
-    /* find all the bands in the row of the one whose Gripper was seized */
-    for (i=0; i<infoPtr->uNumBands; i++) {
-        band = &infoPtr->bands[i];
-	if (HIDDENBAND(band)) continue;
-	if (band->iRow == hitBand->iRow) {
-	    imaxdBand = i;
-	    if (imindBand == -1) imindBand = i;
-	    /* minimum size of each band is size of header plus            */
-	    /* size of minimum child plus offset of child from header plus */
-	    /* one to separate each band.                                  */
-	    if (i < ihitBand)
-	        LHeaderSum += (band->lcx + SEP_WIDTH);
-	    else
-	        RHeaderSum += (band->lcx + SEP_WIDTH);
+    xBand = hitBand->rcBand.left;
+    movement = (infoPtr->dwStyle&CCS_VERT ? ptsmove->y : ptsmove->x)
+                    - (xBand + REBAR_PRE_GRIPPER - infoPtr->ihitoffset);
 
-	}
+    if (movement < 0) {
+        int cxLeft = REBAR_ShrinkBandsRTL(infoPtr, iRowBegin, iHitBand, -movement, TRUE);
+        hitBand->cxEffective += -movement - cxLeft;
+        hitBand->cx = hitBand->cxEffective;
+    } else if (movement > 0) {
+        int cxLeft = REBAR_ShrinkBandsLTR(infoPtr, iHitBand, iRowEnd, movement, TRUE);
+        REBAR_BAND *lpPrev = &infoPtr->bands[prev_band(infoPtr, iHitBand)];
+        lpPrev->cxEffective += movement - cxLeft;
+        lpPrev->cx = lpPrev->cxEffective;
     }
-    if (RHeaderSum) RHeaderSum -= SEP_WIDTH; /* no separator after last band */
-
-    mindBand = &infoPtr->bands[imindBand];
-    maxdBand = &infoPtr->bands[imaxdBand];
-
-    if (imindBand == imaxdBand) return; /* nothing to drag against */
-    if (imindBand == ihitBand) return; /* first band in row, can't drag */
-
-    /* limit movement to inside adjustable bands - Left */
-    if ( (ptsmove->x < mindBand->rcBand.left) ||
-	 (ptsmove->x > maxdBand->rcBand.right) ||
-	 (ptsmove->y < mindBand->rcBand.top) ||
-	 (ptsmove->y > maxdBand->rcBand.bottom))
-        return; /* should swap bands */
 
+    REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd);
     if (infoPtr->dwStyle & CCS_VERT)
-        movement = ptsmove->y - ((hitBand->rcBand.top+REBAR_PRE_GRIPPER) -
-			     infoPtr->ihitoffset);
+        REBAR_CalcVertBand(infoPtr, 0, infoPtr->uNumBands);
     else
-        movement = ptsmove->x - ((hitBand->rcBand.left+REBAR_PRE_GRIPPER) -
-			     infoPtr->ihitoffset);
-    infoPtr->dragNow = *ptsmove;
-
-    TRACE("before: movement=%d (%d,%d), imindBand=%d, ihitBand=%d, imaxdBand=%d, LSum=%d, RSum=%d\n",
-	  movement, ptsmove->x, ptsmove->y, imindBand, ihitBand,
-	  imaxdBand, LHeaderSum, RHeaderSum);
-    REBAR_DumpBand (infoPtr);
-
-    if (movement < 0) {
-
-        /* ***  Drag left/up *** */
-        compress = rcBlt(hitBand) - rcBlt(mindBand) -
-	           LHeaderSum;
-	if (compress < abs(movement)) {
-	    TRACE("limiting left drag, was %d changed to %d\n",
-		  movement, -compress);
-	    movement = -compress;
-	}
-
-        for (i=ihitBand; i>=imindBand; i--) {
-	    band = &infoPtr->bands[i];
-	    if (HIDDENBAND(band)) continue;
-	    if (i == ihitBand) {
-		LEADJ(band, movement);
-	    }
-	    else
-	        movement = REBAR_Shrink (infoPtr, band, movement, i);
-	    band->ccx = rcBw(band);
-	}
-    }
-    else {
-	BOOL first = TRUE;
-
-        /* ***  Drag right/down *** */
-        compress = rcBrb(maxdBand) - rcBlt(hitBand) -
-	           RHeaderSum;
-	if (compress < abs(movement)) {
-	    TRACE("limiting right drag, was %d changed to %d\n",
-		  movement, compress);
-	    movement = compress;
-	}
-        for (i=ihitBand-1; i<=imaxdBand; i++) {
-	    band = &infoPtr->bands[i];
-	    if (HIDDENBAND(band)) continue;
-	    if (first) {
-		first = FALSE;
-		READJ(band, movement);
-	    }
-	    else
-	        movement = REBAR_Shrink (infoPtr, band, movement, i);
-	    band->ccx = rcBw(band);
-	}
-    }
-
-    /* recompute all rectangles */
-    if (infoPtr->dwStyle & CCS_VERT) {
-	REBAR_CalcVertBand (infoPtr, imindBand, imaxdBand+1,
-			    FALSE);
-    }
-    else {
-	REBAR_CalcHorzBand (infoPtr, imindBand, imaxdBand+1,
-			    FALSE);
-    }
-
-    TRACE("bands after adjustment, see band # %d, %d\n",
-	  imindBand, imaxdBand);
-    REBAR_DumpBand (infoPtr);
-
-    SetRect (&newrect,
-	     mindBand->rcBand.left,
-	     mindBand->rcBand.top,
-	     maxdBand->rcBand.right,
-	     maxdBand->rcBand.bottom);
-
-    REBAR_MoveChildWindows (infoPtr, imindBand, imaxdBand+1);
-
-    InvalidateRect (infoPtr->hwndSelf, &newrect, TRUE);
-    UpdateWindow (infoPtr->hwndSelf);
-
+        REBAR_CalcHorzBand(infoPtr, 0, infoPtr->uNumBands);
+    REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd);
 }
 
 
@@ -2677,7 +2027,7 @@ REBAR_DeleteBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     TRACE("setting NEEDS_LAYOUT\n");
     infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
     infoPtr->fStatus |= RESIZE_ANYHOW;
-    REBAR_Layout (infoPtr, NULL, TRUE, FALSE);
+    REBAR_Layout(infoPtr, NULL, TRUE);
 
     return TRUE;
 }
@@ -2779,7 +2129,9 @@ REBAR_GetBandInfoT(REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam, BOOL bUnic
     if (lprbbi->fMask & RBBIM_CHILDSIZE) {
 	lprbbi->cxMinChild = lpBand->cxMinChild;
 	lprbbi->cyMinChild = lpBand->cyMinChild;
-	if (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) {
+        /* to make tests pass we follow Windows behaviour and allow to read these fields only
+         * for RBBS_VARIABLEHEIGHTS bands */
+        if (lprbbi->cbSize >= sizeof (REBARBANDINFOA) && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) {
 	    lprbbi->cyChild    = lpBand->cyChild;
 	    lprbbi->cyMaxChild = lpBand->cyMaxChild;
 	    lprbbi->cyIntegral = lpBand->cyIntegral;
@@ -2882,12 +2234,13 @@ REBAR_GetRect (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     LPRECT lprc = (LPRECT)lParam;
     REBAR_BAND *lpBand;
 
-    if ((iBand < 0) && ((UINT)iBand >= infoPtr->uNumBands))
+    if ((iBand < 0) || ((UINT)iBand >= infoPtr->uNumBands))
 	return FALSE;
     if (!lprc)
 	return FALSE;
 
     lpBand = &infoPtr->bands[iBand];
+    /* For CCS_VERT the coordintes will be swapped - like on Windows */
     CopyRect (lprc, &lpBand->rcBand);
 
     TRACE("band %d, (%d,%d)-(%d,%d)\n", iBand,
@@ -2918,10 +2271,7 @@ REBAR_GetRowHeight (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 	lpBand = &infoPtr->bands[i];
 	if (HIDDENBAND(lpBand)) continue;
 	if (lpBand->iRow != iRow) continue;
-	if (infoPtr->dwStyle & CCS_VERT)
-	    j = lpBand->rcBand.right - lpBand->rcBand.left;
-	else
-	    j = lpBand->rcBand.bottom - lpBand->rcBand.top;
+        j = lpBand->rcBand.bottom - lpBand->rcBand.top;
 	if (j > ret) ret = j;
     }
 
@@ -3051,7 +2401,7 @@ REBAR_InsertBandT(REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam, BOOL bUnico
 
     REBAR_DumpBand (infoPtr);
 
-    REBAR_Layout (infoPtr, NULL, TRUE, FALSE);
+    REBAR_Layout(infoPtr, NULL, TRUE);
     InvalidateRect(infoPtr->hwndSelf, 0, TRUE);
 
     return TRUE;
@@ -3063,6 +2413,8 @@ REBAR_MaximizeBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 {
     REBAR_BAND *lpBand;
     UINT uBand = (UINT) wParam;
+    int iRowBegin, iRowEnd;
+    int cxDesired, extra, extraOrig;
 
     /* Validate */
     if ((infoPtr->uNumBands == 0) ||
@@ -3075,21 +2427,28 @@ REBAR_MaximizeBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 
     lpBand = &infoPtr->bands[uBand];
 
-    if (lParam && (lpBand->fMask & RBBIM_IDEALSIZE)) {
-	/* handle setting ideal size */
-	lpBand->ccx = lpBand->cxIdeal;
-    }
-    else {
-	/* handle setting to max */
-	FIXME("(uBand = %u fIdeal = %s) case not coded\n",
-	      (UINT)wParam, lParam ? "TRUE" : "FALSE");
-	return FALSE;
-    }
-
-    infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
-    REBAR_Layout (infoPtr, 0, TRUE, TRUE);
-    InvalidateRect (infoPtr->hwndSelf, 0, TRUE);
+    if (lParam && (lpBand->cxEffective < lpBand->cxIdeal))
+        cxDesired = lpBand->cxIdeal;
+    else
+        cxDesired = (infoPtr->dwStyle&CCS_VERT ? infoPtr->calcSize.cx : infoPtr->calcSize.cy);
+
+    iRowBegin = get_row_begin_for_band(infoPtr, uBand);
+    iRowEnd   = get_row_end_for_band(infoPtr, uBand);
+    extraOrig = extra = cxDesired - lpBand->cxEffective;
+    if (extra > 0)
+        extra = REBAR_ShrinkBandsRTL(infoPtr, iRowBegin, uBand, extra, TRUE);
+    if (extra > 0)
+        extra = REBAR_ShrinkBandsLTR(infoPtr, next_band(infoPtr, uBand), iRowEnd, extra, TRUE);
+    lpBand->cxEffective += extraOrig - extra;
+    lpBand->cx = lpBand->cxEffective;
+    TRACE("(%d, %ld): Wanted size %d, obtained %d (shrink %d, %d)\n", wParam, lParam, cxDesired, lpBand->cx, extraOrig, extra);
+    REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd);
 
+    if (infoPtr->dwStyle & CCS_VERT)
+        REBAR_CalcVertBand(infoPtr, iRowBegin, iRowEnd);
+    else
+        REBAR_CalcHorzBand(infoPtr, iRowBegin, iRowEnd);
+    REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd);
     return TRUE;
 
 }
@@ -3098,11 +2457,9 @@ REBAR_MaximizeBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 static LRESULT
 REBAR_MinimizeBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 {
-    REBAR_BAND *band, *lpBand;
+    REBAR_BAND *lpBand;
     UINT uBand = (UINT) wParam;
-    RECT newrect;
-    INT imindBand, imaxdBand, iprevBand, startBand, endBand;
-    INT movement, i;
+    int iPrev, iRowBegin, iRowEnd;
 
     /* A "minimize" band is equivalent to "dragging" the gripper
      * of than band to the right till the band is only the size
@@ -3120,110 +2477,31 @@ REBAR_MinimizeBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 
     /* compute amount of movement and validate */
     lpBand = &infoPtr->bands[uBand];
-
-    if (infoPtr->dwStyle & CCS_VERT)
-	movement = lpBand->rcBand.bottom - lpBand->rcBand.top -
-	    lpBand->cxHeader;
-    else
-	movement = lpBand->rcBand.right - lpBand->rcBand.left -
-	    lpBand->cxHeader;
-    if (movement < 0) {
-	ERR("something is wrong, band=(%d,%d)-(%d,%d), cxheader=%d\n",
-	    lpBand->rcBand.left, lpBand->rcBand.top,
-	    lpBand->rcBand.right, lpBand->rcBand.bottom,
-	    lpBand->cxHeader);
-	return FALSE;
-    }
-
-    imindBand = -1;
-    imaxdBand = -1;
-    iprevBand = -1; /* to suppress warning message */
-
-    /* find the first band in row of the one whose is being minimized */
-    for (i=0; i<infoPtr->uNumBands; i++) {
-        band = &infoPtr->bands[i];
-	if (HIDDENBAND(band)) continue;
-	if (band->iRow == lpBand->iRow) {
-	    imaxdBand = i;
-	    if (imindBand == -1) imindBand = i;
-	}
-    }
-
-    /* if the selected band is first in row then need to expand */
-    /* next visible band                                        */
-    if (imindBand == uBand) {
-	band = NULL;
-	movement = -movement;
-	/* find the first visible band to the right of the selected band */
-	for (i=uBand+1; i<=imaxdBand; i++) {
-	    band = &infoPtr->bands[i];
-	    if (!HIDDENBAND(band)) {
-		iprevBand = i;
-		LEADJ(band, movement);
-		band->ccx = rcBw(band);
-		break;
-	    }
-	}
-	/* what case is this */
-	if (iprevBand == -1) {
-	    ERR("no previous visible band\n");
-	    return FALSE;
-	}
-	startBand = uBand;
-	endBand = iprevBand;
-	SetRect (&newrect,
-		 lpBand->rcBand.left,
-		 lpBand->rcBand.top,
-		 band->rcBand.right,
-		 band->rcBand.bottom);
-    }
-    /* otherwise expand previous visible band                   */
-    else {
-	band = NULL;
-	/* find the first visible band to the left of the selected band */
-	for (i=uBand-1; i>=imindBand; i--) {
-	    band = &infoPtr->bands[i];
-	    if (!HIDDENBAND(band)) {
-		iprevBand = i;
-		READJ(band, movement);
-		band->ccx = rcBw(band);
-		break;
-	    }
-	}
-	/* what case is this */
-	if (iprevBand == -1) {
-	    ERR("no previous visible band\n");
-	    return FALSE;
-	}
-	startBand = iprevBand;
-	endBand = uBand;
-	SetRect (&newrect,
-		 band->rcBand.left,
-		 band->rcBand.top,
-		 lpBand->rcBand.right,
-		 lpBand->rcBand.bottom);
-    }
-
-    REBAR_Shrink (infoPtr, lpBand, movement, uBand);
-
-    /* recompute all rectangles */
-    if (infoPtr->dwStyle & CCS_VERT) {
-	REBAR_CalcVertBand (infoPtr, startBand, endBand+1,
-			    FALSE);
-    }
-    else {
-	REBAR_CalcHorzBand (infoPtr, startBand, endBand+1,
-			    FALSE);
+    iPrev = prev_band(infoPtr, uBand);
+    /* if first band in row */
+    if (iPrev < 0 || infoPtr->bands[iPrev].iRow != lpBand->iRow) {
+        int iNext = next_band(infoPtr, uBand);
+        if (iNext < infoPtr->uNumBands && infoPtr->bands[iNext].iRow == lpBand->iRow) {
+            TRACE("(%d): Minimizing the first band in row is by maximizing the second\n", wParam);
+            REBAR_MaximizeBand(infoPtr, iNext, FALSE);
+        }
+        else
+            TRACE("(%d): Only one band in row - nothing to do\n", wParam);
+        return TRUE;
     }
 
-    TRACE("bands after minimize, see band # %d, %d\n",
-	  startBand, endBand);
-    REBAR_DumpBand (infoPtr);
+    infoPtr->bands[iPrev].cxEffective += lpBand->cxEffective - lpBand->lcx;
+    lpBand->cx = lpBand->cxEffective = lpBand->lcx;
 
-    REBAR_MoveChildWindows (infoPtr, startBand, endBand+1);
+    iRowBegin = get_row_begin_for_band(infoPtr, uBand);
+    iRowEnd = get_row_end_for_band(infoPtr, uBand);
+    REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd);
 
-    InvalidateRect (infoPtr->hwndSelf, &newrect, TRUE);
-    UpdateWindow (infoPtr->hwndSelf);
+    if (infoPtr->dwStyle & CCS_VERT)
+        REBAR_CalcVertBand(infoPtr, iRowBegin, iRowEnd);
+    else
+        REBAR_CalcHorzBand(infoPtr, iRowBegin, iRowEnd);
+    REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd);
     return FALSE;
 }
 
@@ -3341,8 +2619,8 @@ REBAR_SetBandInfoT(REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam, BOOL bUnic
 
     REBAR_DumpBand (infoPtr);
 
-    if (bChanged && (lprbbi->fMask & (RBBIM_CHILDSIZE | RBBIM_SIZE))) {
-	  REBAR_Layout (infoPtr, NULL, TRUE, FALSE);
+    if (bChanged && (lprbbi->fMask & (RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE))) {
+	  REBAR_Layout(infoPtr, NULL, TRUE);
 	  InvalidateRect(infoPtr->hwndSelf, 0, 1);
     }
 
@@ -3492,7 +2770,7 @@ REBAR_ShowBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     }
 
     infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
-    REBAR_Layout (infoPtr, NULL, TRUE, FALSE);
+    REBAR_Layout(infoPtr, NULL, TRUE);
     InvalidateRect(infoPtr->hwndSelf, 0, 1);
 
     return TRUE;
@@ -3522,7 +2800,7 @@ REBAR_SizeToRect (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     /* force full _Layout processing */
     TRACE("setting NEEDS_LAYOUT\n");
     infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
-    REBAR_Layout (infoPtr, lpRect, TRUE, FALSE);
+    REBAR_Layout(infoPtr, lpRect, TRUE);
     InvalidateRect (infoPtr->hwndSelf, NULL, TRUE);
     return TRUE;
 }
@@ -3678,9 +2956,9 @@ REBAR_LButtonDown (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
         infoPtr->dragStart.y = (short)HIWORD(lParam);
         infoPtr->dragNow = infoPtr->dragStart;
         if (infoPtr->dwStyle & CCS_VERT)
-            infoPtr->ihitoffset = infoPtr->dragStart.y - (lpBand->rcBand.top+REBAR_PRE_GRIPPER);
+            infoPtr->ihitoffset = infoPtr->dragStart.y - (lpBand->rcBand.left + REBAR_PRE_GRIPPER);
         else
-            infoPtr->ihitoffset = infoPtr->dragStart.x - (lpBand->rcBand.left+REBAR_PRE_GRIPPER);
+            infoPtr->ihitoffset = infoPtr->dragStart.x - (lpBand->rcBand.left + REBAR_PRE_GRIPPER);
     }
     return 0;
 }
@@ -3745,6 +3023,7 @@ REBAR_MouseMove (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     if (infoPtr->iGrabbedBand >= 0)
     {
         REBAR_BAND *band1, *band2;
+        int yPtMove = (infoPtr->dwStyle & CCS_VERT ? ptMove.x : ptMove.y);
     
         if (GetCapture() != infoPtr->hwndSelf)
             ERR("We are dragging but haven't got capture?!?\n");
@@ -3757,25 +3036,13 @@ REBAR_MouseMove (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
             (abs(ptMove.y - infoPtr->dragNow.y) <= mindragy)) return 0;
 
         /* Test for valid drag case - must not be first band in row */
-        if (infoPtr->dwStyle & CCS_VERT) {
-            if ((ptMove.x < band2->rcBand.left) ||
-	      (ptMove.x > band2->rcBand.right) ||
+        if ((yPtMove < band2->rcBand.top) ||
+	      (yPtMove > band2->rcBand.bottom) ||
               ((infoPtr->iGrabbedBand > 0) && (band1->iRow != band2->iRow))) {
-                FIXME("Cannot drag to other rows yet!!\n");
-            }
-            else {
-                REBAR_HandleLRDrag (infoPtr, &ptMove);
-            }
+            FIXME("Cannot drag to other rows yet!!\n");
         }
         else {
-            if ((ptMove.y < band2->rcBand.top) ||
-              (ptMove.y > band2->rcBand.bottom) ||
-              ((infoPtr->iGrabbedBand > 0) && (band1->iRow != band2->iRow))) {
-                FIXME("Cannot drag to other rows yet!!\n");
-            }
-            else {
-                REBAR_HandleLRDrag (infoPtr, &ptMove);
-            }
+            REBAR_HandleLRDrag (infoPtr, &ptMove);
         }
     }
     else
@@ -4114,7 +3381,7 @@ REBAR_SetFont (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 
     if (LOWORD(lParam)) {
         GetClientRect (infoPtr->hwndSelf, &rcClient);
-        REBAR_Layout (infoPtr, &rcClient, FALSE, TRUE);
+        REBAR_Layout(infoPtr, &rcClient, FALSE);
     }
 
     return 0;
@@ -4203,6 +3470,9 @@ REBAR_Size (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 		  LOWORD(lParam), HIWORD(lParam),
 		  rcClient.right, rcClient.bottom);
 	}
+        infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
+        REBAR_Layout(infoPtr, &rcClient, TRUE);
+        return 0;
     }
     else {
 	if ((INT)wParam != SIZE_RESTORED) {
@@ -4245,11 +3515,11 @@ REBAR_Size (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 	      autosize.rcTarget.right, autosize.rcTarget.bottom, lParam);
     }
 
-    if ((infoPtr->calcSize.cx != rcClient.right) ||
-	(infoPtr->calcSize.cy != rcClient.bottom))
-	infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
-
-    REBAR_Layout (infoPtr, &rcClient, TRUE, TRUE);
+    if (((infoPtr->calcSize.cx != rcClient.right) || (infoPtr->calcSize.cy != rcClient.bottom)))
+    {
+        infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
+        REBAR_Layout(infoPtr, &rcClient, TRUE);
+    }
 
     return 0;
 }
@@ -4259,12 +3529,18 @@ static LRESULT
 REBAR_StyleChanged (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 {
     STYLESTRUCT *ss = (STYLESTRUCT *)lParam;
-
+    
     TRACE("current style=%08x, styleOld=%08x, style being set to=%08x\n",
 	  infoPtr->dwStyle, ss->styleOld, ss->styleNew);
     infoPtr->orgStyle = infoPtr->dwStyle = ss->styleNew;
     if (GetWindowTheme (infoPtr->hwndSelf))
         infoPtr->dwStyle &= ~WS_BORDER;
+    /* maybe it should be COMMON_STYLES like in toolbar */
+    if ((ss->styleNew ^ ss->styleOld) & CCS_VERT)
+    {
+        infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
+        REBAR_Layout(infoPtr, NULL, TRUE);
+    }
 
     return FALSE;
 }
diff --git a/dlls/comctl32/tests/rebar.c b/dlls/comctl32/tests/rebar.c
index 5832840..5611f86 100644
--- a/dlls/comctl32/tests/rebar.c
+++ b/dlls/comctl32/tests/rebar.c
@@ -29,6 +29,13 @@
 static HWND hMainWnd;
 static HWND hRebar;
 
+
+#define check_rect(name, val, exp) ok(val.top == exp.top && val.bottom == exp.bottom && \
+    val.left == exp.left && val.right == exp.right, "invalid rect (" name ") (%d,%d) (%d,%d) - expected (%d,%d) (%d,%d)\n", \
+    val.left, val.top, val.right, val.bottom, exp.left, exp.top, exp.right, exp.bottom);
+ 
+#define compare(val, exp, format) ok((val) == (exp), #val " value " format " expected " format "\n", (val), (exp));
+
 #define expect_eq(expr, value, type, format) { type ret = expr; ok((value) == ret, #expr " expected " format "  got " format "\n", (value), (ret)); }
 
 static void rebuild_rebar(HWND *hRebar)
@@ -41,15 +48,324 @@ static void rebuild_rebar(HWND *hRebar)
     SendMessageA(*hRebar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0);
 }
 
+static HWND build_toolbar(int nr, HWND hParent)
+{
+    TBBUTTON btns[8];
+    HWND hToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | CCS_NORESIZE, 0, 0, 0, 0,
+        hParent, (HMENU)5, GetModuleHandle(NULL), NULL);
+    int iBitmapId = 0;
+    int i;
+
+    ok(hToolbar != NULL, "Toolbar creation problem\n");
+    ok(SendMessage(hToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0) == 0, "TB_BUTTONSTRUCTSIZE failed\n");
+    ok(SendMessage(hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
+    ok(SendMessage(hToolbar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0)==1, "WM_SETFONT\n");
+
+    for (i=0; i<5+nr; i++)
+    {
+        btns[i].iBitmap = i;
+        btns[i].idCommand = i;
+        btns[i].fsStyle = BTNS_BUTTON;
+        btns[i].fsState = TBSTATE_ENABLED;
+    }
+
+    switch (nr)
+    {
+        case 0: iBitmapId = IDB_HIST_SMALL_COLOR; break;
+        case 1: iBitmapId = IDB_VIEW_SMALL_COLOR; break;
+        case 2: iBitmapId = IDB_STD_SMALL_COLOR; break;
+    }
+    ok(SendMessage(hToolbar, TB_LOADIMAGES, iBitmapId, (LPARAM)HINST_COMMCTRL) == 0, "TB_LOADIMAGE failed\n");
+    ok(SendMessage(hToolbar, TB_ADDBUTTONS, 5+nr, (LPARAM)btns), "TB_ADDBUTTONS failed\n");
+    return hToolbar;
+}
+
 static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     return DefWindowProcA(hWnd, msg, wParam, lParam);
 }
 
+#if 0  /* use this to generate more tests*/
+
+static void dump_sizes(HWND hRebar)
+{
+    SIZE sz;
+    RECT r;
+    int count;
+    int i, h;
+
+    GetClientRect(hRebar, &r);
+    count = SendMessageA(hRebar, RB_GETROWCOUNT, 0, 0);
+    printf("  { {%d, %d, %d, %d}, %d, %d, {", r.left, r.top, r.right, r.bottom,
+        SendMessageA(hRebar, RB_GETBARHEIGHT, 0, 0), count);
+    if (count == 0)
+        printf("0, ");
+    for (i = 0; i < count; i++)  /* rows */
+        printf("%d, ", SendMessageA(hRebar, RB_GETROWHEIGHT, i, 0));
+    printf("}, ");
+
+    count = SendMessageA(hRebar, RB_GETBANDCOUNT, 0, 0);
+    printf("%d, {", count);
+    if (count == 0)
+        printf("{{0, 0, 0, 0}, 0, 0},");
+    for (i=0; i<count; i++)
+    {
+        REBARBANDINFO rbi;
+        rbi.cbSize = sizeof(REBARBANDINFO);
+        rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE;
+        ok(SendMessageA(hRebar, RB_GETBANDINFOA, i, (LPARAM)&rbi), "RB_GETBANDINFO failed\n");
+        ok(SendMessageA(hRebar, RB_GETRECT, i, (LPARAM)&r), "RB_GETRECT failed\n");
+        printf("%s{ {%3d, %3d, %3d, %3d}, 0x%02x, %d}, ", (i%2==0 ? "\n    " : ""), r.left, r.top, r.right, r.bottom,
+            rbi.fStyle, rbi.cx);
+    }
+    printf("\n  }, }, \n");
+}
+
+#define check_sizes() dump_sizes(hRebar);
+#define check_sizes_todo(todomask) dump_sizes(hRebar);
+
+#else
+
+typedef struct {
+    RECT rc;
+    DWORD fStyle;
+    INT cx;
+} rbband_result_t;
+
+typedef struct {
+    RECT rcClient;
+    int cyBarHeight;
+    int nRows;
+    int cyRowHeights[50];
+    int nBands;
+    rbband_result_t bands[50];
+} rbsize_result_t;
+
+rbsize_result_t rbsize_results[] = {
+  { {0, 0, 672, 0}, 0, 0, {0, }, 0, {{{0, 0, 0, 0}, 0, 0},
+  }, },
+  { {0, 0, 672, 4}, 4, 1, {4, }, 1, {
+    { {  0,   0, 672,   4}, 0x00, 200},
+  }, },
+  { {0, 0, 672, 4}, 4, 1, {4, }, 2, {
+    { {  0,   0, 200,   4}, 0x00, 200}, { {200,   0, 672,   4}, 0x04, 200},
+  }, },
+  { {0, 0, 672, 30}, 30, 1, {30, }, 3, {
+    { {  0,   0, 200,  30}, 0x00, 200}, { {200,   0, 400,  30}, 0x04, 200},
+    { {400,   0, 672,  30}, 0x00, 200},
+  }, },
+  { {0, 0, 672, 34}, 34, 1, {34, }, 4, {
+    { {  0,   0, 200,  34}, 0x00, 200}, { {200,   0, 400,  34}, 0x04, 200},
+    { {400,   0, 604,  34}, 0x00, 200}, { {604,   0, 672,  34}, 0x04, 68},
+  }, },
+  { {0, 0, 672, 34}, 34, 1, {34, }, 4, {
+    { {  0,   0, 200,  34}, 0x00, 200}, { {200,   0, 400,  34}, 0x04, 200},
+    { {400,   0, 604,  34}, 0x00, 200}, { {604,   0, 672,  34}, 0x04, 68},
+  }, },
+  { {0, 0, 672, 34}, 34, 1, {34, }, 4, {
+    { {  0,   0, 200,  34}, 0x00, 200}, { {202,   0, 402,  34}, 0x04, 200},
+    { {404,   0, 604,  34}, 0x00, 200}, { {606,   0, 672,  34}, 0x04, 66},
+  }, },
+  { {0, 0, 672, 70}, 70, 2, {34, 34, }, 5, {
+    { {  0,   0, 142,  34}, 0x00, 200}, { {144,   0, 557,  34}, 0x00, 200},
+    { {559,   0, 672,  34}, 0x04, 200}, { {  0,  36, 200,  70}, 0x00, 200},
+    { {202,  36, 672,  70}, 0x04, 66},
+  }, },
+  { {0, 0, 672, 34}, 34, 1, {34, }, 5, {
+    { {  0,   0, 167,  34}, 0x00, 200}, { {169,   0, 582,  34}, 0x00, 200},
+    { {559,   0, 759,  34}, 0x08, 200}, { {584,   0, 627,  34}, 0x00, 200},
+    { {629,   0, 672,  34}, 0x04, 66},
+  }, },
+  { {0, 0, 672, 34}, 34, 1, {34, }, 4, {
+    { {  0,   0, 167,  34}, 0x00, 200}, { {169,   0, 582,  34}, 0x00, 200},
+    { {584,   0, 627,  34}, 0x00, 200}, { {629,   0, 672,  34}, 0x04, 66},
+  }, },
+  { {0, 0, 672, 34}, 34, 1, {34, }, 3, {
+    { {  0,   0, 413,  34}, 0x00, 200}, { {415,   0, 615,  34}, 0x00, 200},
+    { {617,   0, 672,  34}, 0x04, 66},
+  }, },
+  { {0, 0, 672, 34}, 34, 1, {34, }, 2, {
+    { {  0,   0, 604,  34}, 0x00, 200}, { {606,   0, 672,  34}, 0x04, 66},
+  }, },
+  { {0, 0, 672, 0}, 0, 0, {0, }, 0, {{{0, 0, 0, 0}, 0, 0},
+  }, },
+  { {0, 0, 672, 65}, 65, 1, {65, }, 3, {
+    { {  0,   0,  90,  65}, 0x40, 90}, { { 90,   0, 180,  65}, 0x40, 90},
+    { {180,   0, 672,  65}, 0x40, 90},
+  }, },
+  { {0, 0, 0, 226}, 0, 0, {0, }, 0, {{{0, 0, 0, 0}, 0, 0},
+  }, },
+  { {0, 0, 65, 226}, 65, 1, {65, }, 1, {
+    { {  0,   0, 226,  65}, 0x40, 90},
+  }, },
+  { {0, 0, 65, 226}, 65, 1, {65, }, 2, {
+    { {  0,   0,  90,  65}, 0x40, 90}, { { 90,   0, 226,  65}, 0x40, 90},
+  }, },
+  { {0, 0, 65, 226}, 65, 1, {65, }, 3, {
+    { {  0,   0,  90,  65}, 0x40, 90}, { { 90,   0, 163,  65}, 0x40, 90},
+    { {163,   0, 226,  65}, 0x40, 90},
+  }, },
+};
+
+static int rbsize_numtests = 0;
+
+#define check_sizes_todo(todomask) { \
+        RECT rc; \
+        REBARBANDINFO rbi; \
+        int count, i/*, mask=(todomask)*/; \
+        rbsize_result_t *res = &rbsize_results[rbsize_numtests]; \
+        assert(rbsize_numtests < sizeof(rbsize_results)/sizeof(rbsize_results[0])); \
+        GetClientRect(hRebar, &rc); \
+        check_rect("client", rc, res->rcClient); \
+        count = SendMessage(hRebar, RB_GETROWCOUNT, 0, 0); \
+        compare(count, res->nRows, "%d"); \
+        for (i=0; i<min(count, res->nRows); i++) { \
+            int height = SendMessageA(hRebar, RB_GETROWHEIGHT, 0, 0);\
+            ok(height == res->cyRowHeights[i], "Height mismatch for row %d - %d vs %d\n", i, res->cyRowHeights[i], height); \
+        } \
+        count = SendMessage(hRebar, RB_GETBANDCOUNT, 0, 0); \
+        compare(count, res->nBands, "%d"); \
+        for (i=0; i<min(count, res->nBands); i++) { \
+            ok(SendMessageA(hRebar, RB_GETRECT, i, (LPARAM)&rc) == 1, "RB_ITEMRECT\n"); \
+            if (!(res->bands[i].fStyle & RBBS_HIDDEN)) \
+                check_rect("band", rc, res->bands[i].rc); \
+            rbi.cbSize = sizeof(REBARBANDINFO); \
+            rbi.fMask = RBBIM_STYLE | RBBIM_SIZE; \
+            ok(SendMessageA(hRebar, RB_GETBANDINFO,  i, (LPARAM)&rbi) == 1, "RB_GETBANDINFO\n"); \
+            compare(rbi.fStyle, res->bands[i].fStyle, "%x"); \
+            compare(rbi.cx, res->bands[i].cx, "%d"); \
+        } \
+        rbsize_numtests++; \
+    }
+
+#define check_sizes() check_sizes_todo(0)
+
+#endif
+
+static void layout_test()
+{
+    HWND hRebar = NULL;
+    REBARBANDINFO rbi;
+
+    rebuild_rebar(&hRebar);
+    check_sizes();
+    rbi.cbSize = sizeof(rbi);
+    rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD;
+    rbi.cx = 200;
+    rbi.cxMinChild = 100;
+    rbi.cyMinChild = 30;
+    rbi.hwndChild = NULL;
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    rbi.fMask |= RBBIM_STYLE;
+    rbi.fStyle = RBBS_CHILDEDGE;
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    rbi.fStyle = 0;
+    rbi.cx = 200;
+    rbi.cxMinChild = 30;
+    rbi.cyMinChild = 30;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    rbi.fStyle = RBBS_CHILDEDGE;
+    rbi.cx = 68;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | RBS_BANDBORDERS);
+    check_sizes();      /* a style change won't start a relayout */
+    rbi.fMask = RBBIM_SIZE;
+    rbi.cx = 66;
+    SendMessageA(hRebar, RB_SETBANDINFO, 3, (LPARAM)&rbi);
+    check_sizes();      /* here it will be relayouted */
+
+    /* this will force a new row */
+    rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD;
+    rbi.cx = 200;
+    rbi.cxMinChild = 400;
+    rbi.cyMinChild = 30;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, 1, (LPARAM)&rbi);
+    check_sizes();
+
+    rbi.fMask = RBBIM_STYLE;
+    rbi.fStyle = RBBS_HIDDEN;
+    SendMessageA(hRebar, RB_SETBANDINFO, 2, (LPARAM)&rbi);
+    check_sizes();
+
+    SendMessageA(hRebar, RB_DELETEBAND, 2, 0);
+    check_sizes();
+    SendMessageA(hRebar, RB_DELETEBAND, 0, 0);
+    check_sizes();
+    SendMessageA(hRebar, RB_DELETEBAND, 1, 0);
+    check_sizes();
+
+    /* VARHEIGHT resizing test on a horizontal rebar */
+    rebuild_rebar(&hRebar);
+    SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | RBS_AUTOSIZE);
+    check_sizes();
+    rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
+    rbi.fStyle = RBBS_VARIABLEHEIGHT;
+    rbi.cxMinChild = 50;
+    rbi.cyMinChild = 10;
+    rbi.cyIntegral = 11;
+    rbi.cyChild = 70;
+    rbi.cyMaxChild = 200;
+    rbi.cx = 90;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+
+    rbi.cyChild = 50;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+
+    rbi.cyMinChild = 40;
+    rbi.cyChild = 50;
+    rbi.cyIntegral = 5;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    /* VARHEIGHT resizing on a vertical rebar */
+    rebuild_rebar(&hRebar);
+    SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | CCS_VERT | RBS_AUTOSIZE);
+    check_sizes();
+    rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
+    rbi.fStyle = RBBS_VARIABLEHEIGHT;
+    rbi.cxMinChild = 50;
+    rbi.cyMinChild = 10;
+    rbi.cyIntegral = 11;
+    rbi.cyChild = 70;
+    rbi.cyMaxChild = 90;
+    rbi.cx = 90;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    rbi.cyChild = 50;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    rbi.cyMinChild = 40;
+    rbi.cyChild = 50;
+    rbi.cyIntegral = 5;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    DestroyWindow(hRebar);
+}
+
 static void expect_band_content(UINT uBand, UINT fStyle, COLORREF clrFore,
     COLORREF clrBack, LPCSTR lpText, int iImage, HWND hwndChild,
     UINT cxMinChild, UINT cyMinChild, UINT cx, HBITMAP hbmBack, UINT wID,
-    /*UINT cyChild, UINT cyMaxChild, UINT cyIntegral,*/ UINT cxIdeal, LPARAM lParam,
+    UINT cyChild, UINT cyMaxChild, UINT cyIntegral, UINT cxIdeal, LPARAM lParam,
     UINT cxHeader)
 {
     CHAR buf[MAX_PATH] = "abc";
@@ -74,12 +390,12 @@ static void expect_band_content(UINT uBand, UINT fStyle, COLORREF clrFore,
     expect_eq(rb.cx, cx, int, "%d");
     expect_eq(rb.hbmBack, hbmBack, HBITMAP, "%p");
     expect_eq(rb.wID, wID, int, "%d");
-    /* in Windows the values of cyChild, cyMaxChild and cyIntegral can't be read */
-    todo_wine expect_eq(rb.cyChild, 0xdddddddd, int, "%x");
-    todo_wine expect_eq(rb.cyMaxChild, 0xdddddddd, int, "%x");
-    todo_wine expect_eq(rb.cyIntegral, 0xdddddddd, int, "%x");
+    /* the values of cyChild, cyMaxChild and cyIntegral can't be read unless the band is RBBS_VARIABLEHEIGHT */
+    expect_eq(rb.cyChild, cyChild, int, "%x");
+    expect_eq(rb.cyMaxChild, cyMaxChild, int, "%x");
+    expect_eq(rb.cyIntegral, cyIntegral, int, "%x");
     expect_eq(rb.cxIdeal, cxIdeal, int, "%d");
-    expect_eq(rb.lParam, lParam, LPARAM, "%lx");
+    expect_eq(rb.lParam, lParam, LPARAM, "%ld");
     expect_eq(rb.cxHeader, cxHeader, int, "%d");
 }
 
@@ -93,7 +409,7 @@ static void bandinfo_test()
     rb.cbSize = sizeof(REBARBANDINFO);
     rb.fMask = 0;
     ok(SendMessageA(hRebar, RB_INSERTBANDA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
-    expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 0, 0, 0, NULL, 0, 0, 0, 0);
+    expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 0, 0, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 0);
 
     rb.fMask = RBBIM_CHILDSIZE;
     rb.cxMinChild = 15;
@@ -102,37 +418,37 @@ static void bandinfo_test()
     rb.cyMaxChild = 20;
     rb.cyIntegral = 10;
     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
-    expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 15, 20, 0, NULL, 0, 0, 0, 0);
+    expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 0);
 
     rb.fMask = RBBIM_TEXT;
     rb.lpText = szABC;
     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
-    expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0, 0, 35);
+    expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 35);
 
     rb.cbSize = sizeof(REBARBANDINFO);
     rb.fMask = 0;
     ok(SendMessageA(hRebar, RB_INSERTBANDA, 1, (LPARAM)&rb), "RB_INSERTBAND failed\n");
-    expect_band_content(1, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 0, 0, 0, NULL, 0, 0, 0, 9);
-    expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0, 0, 40);
+    expect_band_content(1, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 0, 0, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 9);
+    expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 40);
 
     rb.fMask = RBBIM_HEADERSIZE;
     rb.cxHeader = 50;
     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
-    expect_band_content(0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0, 0, 50);
+    expect_band_content(0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 50);
 
     rb.cxHeader = 5;
     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
-    expect_band_content(0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0, 0, 5);
+    expect_band_content(0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 5);
 
     rb.fMask = RBBIM_TEXT;
     rb.lpText = szABCD;
     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
-    expect_band_content(0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABCD", -1, NULL, 15, 20, 0, NULL, 0, 0, 0, 5);
+    expect_band_content(0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABCD", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 5);
     rb.fMask = RBBIM_STYLE | RBBIM_TEXT;
-    rb.fStyle = 0;
+    rb.fStyle = RBBS_VARIABLEHEIGHT;
     rb.lpText = szABC;
     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
-    expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0, 0, 40);
+    expect_band_content(0, RBBS_VARIABLEHEIGHT, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 20, 0x7fffffff, 0, 0, 0, 40);
 
     DestroyWindow(hRebar);
 }
@@ -161,11 +477,13 @@ START_TEST(rebar)
     RegisterClassA(&wc);
     
     hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, 
-      CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
+      CW_USEDEFAULT, CW_USEDEFAULT, 680, 226+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYSIZEFRAME),
+      NULL, NULL, GetModuleHandleA(NULL), 0);
     GetClientRect(hMainWnd, &rc);
     ShowWindow(hMainWnd, SW_SHOW);
 
     bandinfo_test();
+    layout_test();
     PostQuitMessage(0);
     while(GetMessageA(&msg,0,0,0)) {
         TranslateMessage(&msg);
-- 
1.4.4.2


More information about the wine-patches mailing list