From f0a7a74666e2cf9aa1213ea638c4d899f86f19e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Zalewski?= Date: Mon, 19 Feb 2007 13:56:51 +0100 Subject: [PATCH] comctl32: rebar: Rewrite the layout code. --- dlls/comctl32/rebar.c | 1777 ++++++++++------------------------- dlls/comctl32/tests/rebar.c | 420 ++++++++- 2 files changed, 922 insertions(+), 1275 deletions(-) diff --git a/dlls/comctl32/rebar.c b/dlls/comctl32/rebar.c index 9550eb55bee..cfa59f22e06 100644 --- a/dlls/comctl32/rebar.c +++ b/dlls/comctl32/rebar.c @@ -127,20 +127,14 @@ 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 */ UINT fDraw; /* drawing flags, reset only by _Layout */ UINT uCDret; /* last return from NM_CUSTOMDRAW */ - RECT rcoldBand; /* previous calculated band rectangle */ RECT rcBand; /* calculated band rectangle */ RECT rcGripper; /* calculated gripper rectangle */ RECT rcCapImage; /* calculated caption image rectangle */ @@ -161,12 +155,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 +240,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 +261,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); @@ -429,8 +407,8 @@ REBAR_DumpBand (REBAR_INFO *iP) if (pB->fMask & RBBIM_STYLE) TRACE("band # %u: style=0x%08x (%s)\n", i, pB->fStyle, REBAR_FmtStyle(pB->fStyle)); - TRACE("band # %u: uMinH=%u xHeader=%u", - i, pB->uMinHeight, pB->cxHeader); + TRACE("band # %u: xHeader=%u", + i, pB->cxHeader); if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_LPARAM )) { if (pB->fMask & RBBIM_SIZE) TRACE(" cx=%u", pB->cx); @@ -446,8 +424,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 +439,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 +559,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 +571,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 +667,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 +701,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; ibands[i]; @@ -922,8 +719,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); @@ -960,11 +755,6 @@ REBAR_CalcHorzBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify) SetRect (&lpBand->rcCapText, lpBand->rcCapImage.right+REBAR_POST_IMAGE, lpBand->rcBand.top+1, lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1); - /* update band height - if (lpBand->uMinHeight < infoPtr->imageSize.cy + 2) { - lpBand->uMinHeight = infoPtr->imageSize.cy + 2; - lpBand->rcBand.bottom = lpBand->rcBand.top + lpBand->uMinHeight; - } */ } else { /* set initial caption text rectangle */ @@ -980,12 +770,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 +791,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 +810,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; ibands[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 +841,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 +854,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 +867,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,19 +880,14 @@ 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); - /* update band height * - if (lpBand->uMinHeight < infoPtr->imageSize.cx + 2) { - lpBand->uMinHeight = infoPtr->imageSize.cx + 2; - lpBand->rcBand.right = lpBand->rcBand.left + lpBand->uMinHeight; - } */ + rcBand.left, lpBand->rcCapImage.bottom+REBAR_POST_IMAGE, + rcBand.right, rcBand.top+lpBand->cxHeader); } 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 +898,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 +945,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 +1000,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 +1061,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 +1075,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 +1158,308 @@ REBAR_MoveChildWindows (REBAR_INFO *infoPtr, UINT start, UINT endplus) } +static void swap_size_if_vert(REBAR_INFO *infoPtr, SIZE *size) +{ + if (infoPtr->dwStyle & CCS_VERT) + { + LONG tmp = size->cx; + size->cx = size->cy; + size->cy = tmp; + } +} + +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; +} + +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; +} + +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 + iLastBand = iBand; + } + return iLastBand; +} + +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; +} + +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]; + + 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; + } +} + +/* The rationale of this function is probably as follows: if we have some space + * to distribute we want to add it to a band on the right. However we don't want + * to unminimize a minimized band so we search for a band that is big enough. + * For some reason "big enough" is defined as bigger than the minimum size of the + * first band in the row + */ +static REBAR_BAND *REBAR_FindBandToGrow(REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand) +{ + INT iLcx = 0, i; + + iLcx = infoPtr->bands[iBeginBand].lcx; + + for (i = prev_band(infoPtr, iEndBand); i >= iBeginBand; i = prev_band(infoPtr, i)) + if (infoPtr->bands[i].cxEffective > iLcx && !(infoPtr->bands[i].fStyle&RBBS_FIXEDSIZE)) + break; + + if (i < iBeginBand) + for (i = prev_band(infoPtr, iEndBand); i >= iBeginBand; i = prev_band(infoPtr, i)) + if (infoPtr->bands[i].lcx == iLcx) + break; + + TRACE("Extra space for row [%d..%d) should be added to band %d\n", iBeginBand, iEndBand, i); + return &infoPtr->bands[i]; +} + +static int REBAR_ShrinkBandsRTL(REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT cxShrink, BOOL bEnforce) +{ + REBAR_BAND *lpBand; + INT width, i; + + 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]; + + width = max(lpBand->cxEffective - cxShrink, (int)lpBand->lcx); + cxShrink -= lpBand->cxEffective - width; + lpBand->cxEffective = width; + if (bEnforce && lpBand->cx > lpBand->cxEffective) + lpBand->cx = lpBand->cxEffective; + if (cxShrink == 0) + break; + } + return cxShrink; +} + + +static int REBAR_ShrinkBandsLTR(REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT cxShrink, BOOL bEnforce) +{ + REBAR_BAND *lpBand; + INT width, i; + + 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]; + + 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; +} + +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); + + 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; + } + + 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)); + } + } + return yPos + yMaxHeight; +} + +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; + + TRACE("Adjusting row [%d;%d). Width: %d\n", iBeginBand, iEndBand, cx); + for (i = iBeginBand; i < iEndBand; i++) + infoPtr->bands[i].iRow = *piRow; + + /* 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)++; +} 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. */ +REBAR_Layout(REBAR_INFO *infoPtr, LPRECT lpRect, BOOL notify) { - 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; + REBAR_BAND *lpBand; + RECT rcAdj; + INT adjcx, adjcy, i; + INT rowstart = 0; + INT row = 0; + INT xMin, yPos; + INT cyTarget; + const INT yInit = 0; 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); - + cyTarget = 0; 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; + rcAdj = *lpRect; + cyTarget = get_rect_cy(infoPtr, lpRect); + } else if (infoPtr->dwStyle & CCS_NORESIZE || GetParent(infoPtr->hwndSelf) == NULL) + GetClientRect(infoPtr->hwndSelf, &rcAdj); else - origheight = infoPtr->calcSize.cy; - origrows = infoPtr->uNumRows; + GetClientRect(GetParent(infoPtr->hwndSelf), &rcAdj); + TRACE("adjustment rect is (%d,%d)-(%d,%d)\n", rcAdj.left, rcAdj.top, rcAdj.right, rcAdj.bottom); - initx = 0; - inity = 0; + adjcx = get_rect_cx(infoPtr, &rcAdj); + adjcy = get_rect_cy(infoPtr, &rcAdj); - /* ******* Start Phase 1 - all bands on row at minimum size ******* */ + 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; + } - 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; + yPos = yInit; + xMin = 0; + /* divide rows */ + i = 0; + for (i = 0; i < infoPtr->uNumBands; i++) + { + lpBand = &infoPtr->bands[i]; + if (HIDDENBAND(lpBand)) continue; - 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; - - /* 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); - - /* separator from previous band */ - cxsep = (cntonrow == 0) ? 0 : SEP_WIDTH; - cx = lpBand->lcx; - - /* In native, 0 as one of the coordinates means no limit */ - if (infoPtr->dwStyle & CCS_VERT) - dobreak = (adjcy && (y + cx + cxsep > adjcy)); + 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 - dobreak = (adjcx && (x + cx + cxsep > adjcx)); + xMin += SEP_WIDTH; - /* 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)) { + xMin += lpBand->lcx; + } + REBAR_LayoutRow(infoPtr, rowstart, infoPtr->uNumBands, adjcx, &row, &yPos); - 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; - } - } + if (!(infoPtr->dwStyle & RBS_VARHEIGHT)) + yPos = REBAR_SetBandsHeight(infoPtr, 0, infoPtr->uNumBands, yInit); - 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++; - - } /* for (i = 0; i < infoPtr->uNumBands... */ + infoPtr->uNumRows = row; if (infoPtr->dwStyle & CCS_VERT) - x += mcy; + REBAR_CalcVertBand(infoPtr, 0, infoPtr->uNumBands); else - y += mcy; - - 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; - } - } - - if (infoPtr->uNumBands) - infoPtr->uNumRows = row + 1; - - /* ******* End Phase 1 - all bands on row at minimum size ******* */ - - - /* ******* Start Phase 1a - Adjust heights for RBS_VARHEIGHT off ******* */ - - mmcy = 0; - if (!(infoPtr->dwStyle & RBS_VARHEIGHT)) { - INT xy; - - /* get the max height of all bands */ - for (i=0; iuNumBands; 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); - } - - /* now adjust all rectangles by using the height found above */ - xy = 0; - row = 0; - for (i=0; iuNumBands; 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; - } - } - - /* set the x/y values to the correct maximum */ - if (infoPtr->dwStyle & CCS_VERT) - x = xy + mmcy; - else - y = xy + mmcy; - } - - /* ******* End Phase 1a - Adjust heights for RBS_VARHEIGHT off ******* */ - - - /* ******* Start Phase 2 - split rows till adjustment height full ******* */ - - /* 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; - -/* 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; juNumBands; 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 */ - } - } - } - } - - /* ******* End Phase 2 - split rows till adjustment height full ******* */ - - - /* ******* Start Phase 2a - mark first and last band in each ******* */ - - 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; - } - else if( prevBand->iRow == lpBand->iRow ) - prevBand = lpBand; - else { - prevBand->fDraw |= DRAW_LAST_IN_ROW; - lpBand->fDraw |= DRAW_FIRST_IN_ROW; - prevBand = lpBand; - } - } - 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 */ - - if (((infoPtr->dwStyle & CCS_VERT) ? clientcx > x : clientcy > y) && - infoPtr->uNumBands) { - INT diff, i; - UINT j; - - diff = (infoPtr->dwStyle & CCS_VERT) ? clientcx - x : clientcy - y; - - /* 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; - } - - /* ******* 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; iuNumBands; i++) { - lpBand = &infoPtr->bands[i]; - if (HIDDENBAND(lpBand)) - continue; - - /* not righthand bands */ - if( !(lpBand->fDraw & DRAW_LAST_IN_ROW) ) - lpBand->fDraw |= DRAW_RIGHTSEP; - - /* not the last row */ - if( lpBand->iRow != infoPtr->uNumRows ) - lpBand->fDraw |= DRAW_BOTTOMSEP; - } - } - - /* Distribute the extra space on the horizontal and adjust */ - /* all bands in row to same height. */ - mcy = 0; - startband = -1; - for (i=0; iuNumBands; i++) { - - lpBand = &infoPtr->bands[i]; - - if( lpBand->fDraw & DRAW_FIRST_IN_ROW ) - { - startband = i; - mcy = 0; - } - - if ( (mcy < ircBw(lpBand)) && !HIDDENBAND(lpBand) ) - mcy = ircBw(lpBand); - - 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); - } - } - - /* 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); - } - } - - /* ******* End Phase 3 - adjust all bands for width full ******* */ - + 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; - } + + 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; + + 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 +1478,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 +1493,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 +1572,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 +1653,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 +1729,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 +1737,17 @@ REBAR_InternalEraseBkGnd (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam, REC oldrow = -1; for(i=0; iuNumBands; 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 +1771,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 +1815,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 + /* 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 +1828,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 +1862,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 +1919,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 +1928,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 +1946,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; iuNumBands; 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); - - } - } - 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 */ - - if (infoPtr->dwStyle & CCS_VERT) - movement = ptsmove->y - ((hitBand->rcBand.top+REBAR_PRE_GRIPPER) - - infoPtr->ihitoffset); - 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); + xBand = hitBand->rcBand.left; + movement = (infoPtr->dwStyle&CCS_VERT ? ptsmove->y : ptsmove->x) + - (xBand + REBAR_PRE_GRIPPER - infoPtr->ihitoffset); 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); - } + 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; } - /* 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_SetRowRectsX(infoPtr, iRowBegin, iRowEnd); + if (infoPtr->dwStyle & CCS_VERT) + REBAR_CalcVertBand(infoPtr, 0, infoPtr->uNumBands); + else + REBAR_CalcHorzBand(infoPtr, 0, infoPtr->uNumBands); + REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd); } @@ -2677,7 +2011,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 +2113,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 +2218,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 +2255,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 +2385,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 +2397,9 @@ REBAR_MaximizeBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) { REBAR_BAND *lpBand; UINT uBand = (UINT) wParam; + int iRowBegin, iRowEnd; + int cxDesired, extra, extraOrig; + int cxIdealBand; /* Validate */ if ((infoPtr->uNumBands == 0) || @@ -3075,21 +2412,29 @@ 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; - } + cxIdealBand = lpBand->cxIdeal + lpBand->cxHeader + REBAR_POST_CHILD; + if (lParam && (lpBand->cxEffective < cxIdealBand)) + cxDesired = cxIdealBand; + else + cxDesired = (infoPtr->dwStyle&CCS_VERT ? infoPtr->calcSize.cy : infoPtr->calcSize.cx); - infoPtr->fStatus |= BAND_NEEDS_LAYOUT; - REBAR_Layout (infoPtr, 0, TRUE, TRUE); - InvalidateRect (infoPtr->hwndSelf, 0, TRUE); + 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 +2443,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 +2463,32 @@ REBAR_MinimizeBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) /* compute amount of movement and validate */ lpBand = &infoPtr->bands[uBand]; + 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; + } + + infoPtr->bands[iPrev].cxEffective += lpBand->cxEffective - lpBand->lcx; + infoPtr->bands[iPrev].cx = infoPtr->bands[iPrev].cxEffective; + lpBand->cx = lpBand->cxEffective = lpBand->lcx; + + iRowBegin = get_row_begin_for_band(infoPtr, uBand); + iRowEnd = get_row_end_for_band(infoPtr, uBand); + REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd); if (infoPtr->dwStyle & CCS_VERT) - movement = lpBand->rcBand.bottom - lpBand->rcBand.top - - lpBand->cxHeader; + REBAR_CalcVertBand(infoPtr, iRowBegin, iRowEnd); 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; iuNumBands; 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); - } - - TRACE("bands after minimize, see band # %d, %d\n", - startBand, endBand); - REBAR_DumpBand (infoPtr); - - REBAR_MoveChildWindows (infoPtr, startBand, endBand+1); - - InvalidateRect (infoPtr->hwndSelf, &newrect, TRUE); - UpdateWindow (infoPtr->hwndSelf); + REBAR_CalcHorzBand(infoPtr, iRowBegin, iRowEnd); + REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd); return FALSE; } @@ -3341,8 +2606,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 +2757,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 +2787,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 +2943,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,7 +3010,8 @@ 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 +3023,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 +3368,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 +3457,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 +3502,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; } @@ -4265,6 +3522,12 @@ REBAR_StyleChanged (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 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 23497efcc7f..a17e002dc40 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,391 @@ 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; + btns[i].iString = 0; + } + + 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; ircClient); \ + count = SendMessage(hRebar, RB_GETROWCOUNT, 0, 0); \ + compare(count, res->nRows, "%d"); \ + for (i=0; inRows); 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; inBands); 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 add_band_w(HWND hRebar, LPCSTR lpszText, int cxMinChild, int cx, int cxIdeal) +{ + CHAR buffer[MAX_PATH]; + REBARBANDINFO rbi; + + if (lpszText != NULL) + strcpy(buffer, lpszText); + rbi.cbSize = sizeof(rbi); + rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_TEXT; + rbi.cx = cx; + rbi.cxMinChild = cxMinChild; + rbi.cxIdeal = cxIdeal; + rbi.cyMinChild = 20; + rbi.hwndChild = build_toolbar(1, hRebar); + rbi.lpText = (lpszText ? buffer : NULL); + SendMessage(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi); +} + +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(); + + rebuild_rebar(&hRebar); + add_band_w(hRebar, "ABC", 70, 40, 100); + add_band_w(hRebar, NULL, 40, 70, 100); + add_band_w(hRebar, NULL, 170, 240, 100); + add_band_w(hRebar, "MMMMMMM", 60, 60, 100); + add_band_w(hRebar, NULL, 200, 200, 100); + check_sizes(); + SendMessageA(hRebar, RB_MAXIMIZEBAND, 1, TRUE); + check_sizes(); + SendMessageA(hRebar, RB_MAXIMIZEBAND, 1, TRUE); + check_sizes(); + SendMessageA(hRebar, RB_MAXIMIZEBAND, 2, FALSE); + check_sizes(); + SendMessageA(hRebar, RB_MINIMIZEBAND, 2, 0); + check_sizes(); + SendMessageA(hRebar, RB_MINIMIZEBAND, 0, 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 +457,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 +476,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 +485,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); } @@ -159,13 +542,14 @@ START_TEST(rebar) wc.lpszClassName = "MyTestWnd"; wc.lpfnWndProc = MyWndProc; 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);