Mikołaj Zalewski : comctl32: rebar: An implementation of RB_SIZETORECT.
Alexandre Julliard
julliard at winehq.org
Wed Feb 27 08:03:18 CST 2008
Module: wine
Branch: master
Commit: 480c0d721585025f472ecd06de2543ef7ff6450e
URL: http://source.winehq.org/git/wine.git/?a=commit;h=480c0d721585025f472ecd06de2543ef7ff6450e
Author: Mikołaj Zalewski <mikolaj at zalewski.pl>
Date: Tue Feb 26 21:09:01 2008 +0100
comctl32: rebar: An implementation of RB_SIZETORECT.
---
dlls/comctl32/rebar.c | 146 ++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 121 insertions(+), 25 deletions(-)
diff --git a/dlls/comctl32/rebar.c b/dlls/comctl32/rebar.c
index 0784e61..cd2861c 100644
--- a/dlls/comctl32/rebar.c
+++ b/dlls/comctl32/rebar.c
@@ -2,6 +2,7 @@
* Rebar control
*
* Copyright 1998, 1999 Eric Kohl
+ * Copyright 2007, 2008 Mikolaj Zalewski
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -116,10 +117,12 @@ typedef struct
LPARAM lParam;
UINT cxHeader;
- INT cxEffective; /* current cx for band */
+ INT cxEffective; /* current cx for band */
+ UINT cyHeader; /* the height of the header */
UINT lcx; /* minimum cx for band */
UINT lcy; /* minimum cy for band */
+ UINT cyRowSoFar; /* for RBS_VARHEIGHT - the height of the row if it would break on this band (set by _Layout) */
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 */
@@ -450,15 +453,21 @@ static int get_rect_cy(const REBAR_INFO *infoPtr, const RECT *lpRect)
return lpRect->bottom - lpRect->top;
}
-static void round_child_height(REBAR_BAND *lpBand, int cyHeight)
+static int round_child_height(REBAR_BAND *lpBand, int cyHeight)
{
int cy = 0;
if (lpBand->cyIntegral == 0)
- return;
+ return cyHeight;
cy = max(cyHeight - (int)lpBand->cyMinChild, 0);
cy = lpBand->cyMinChild + (cy/lpBand->cyIntegral) * lpBand->cyIntegral;
cy = min(cy, lpBand->cyMaxChild);
- lpBand->cyChild = cy;
+ return cy;
+}
+
+static void update_min_band_height(const REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
+{
+ lpBand->lcy = max(lpBand->cyHeader,
+ (lpBand->hwndChild ? lpBand->cyChild + REBARSPACE(lpBand) : REBAR_NO_CHILD_HEIGHT));
}
static void
@@ -1227,6 +1236,7 @@ static int REBAR_SetBandsHeight(const REBAR_INFO *infoPtr, INT iBeginBand, INT i
for (i = iBeginBand; i < iEndBand; i = next_band(infoPtr, i))
{
lpBand = &infoPtr->bands[i];
+ lpBand->cyRowSoFar = yMaxHeight;
yMaxHeight = max(yMaxHeight, lpBand->lcy);
}
TRACE("Bands [%d; %d) height: %d\n", iBeginBand, iEndBand, yMaxHeight);
@@ -1380,6 +1390,109 @@ REBAR_Layout(REBAR_INFO *infoPtr, const RECT *lpRect)
}
}
+static int
+REBAR_SizeChildrenToHeight(const REBAR_INFO *infoPtr, int iBeginBand, int iEndBand, int extra, BOOL *fChanged)
+{
+ int cyBandsOld;
+ int cyBandsNew = 0;
+ int i;
+
+ TRACE("[%d;%d) by %d\n", iBeginBand, iEndBand, extra);
+
+ cyBandsOld = infoPtr->bands[iBeginBand].rcBand.bottom - infoPtr->bands[iBeginBand].rcBand.top;
+ for (i = iBeginBand; i < iEndBand; i = next_band(infoPtr, i))
+ {
+ REBAR_BAND *lpBand = &infoPtr->bands[i];
+ int cyMaxChild = cyBandsOld - REBARSPACE(lpBand) + extra;
+ int cyChild = round_child_height(lpBand, cyMaxChild);
+
+ if (lpBand->hwndChild && cyChild != lpBand->cyChild && (lpBand->fStyle & RBBS_VARIABLEHEIGHT))
+ {
+ TRACE("Resizing %d: %d -> %d [%d]\n", i, lpBand->cyChild, cyChild, lpBand->cyMaxChild);
+ *fChanged = TRUE;
+ lpBand->cyChild = cyChild;
+ lpBand->fDraw |= NTF_INVALIDATE;
+ update_min_band_height(infoPtr, lpBand);
+ }
+ cyBandsNew = max(cyBandsNew, lpBand->lcy);
+ }
+ return cyBandsNew - cyBandsOld;
+}
+
+/* worker function for RB_SIZETORECT and RBS_AUTOSIZE */
+static VOID
+REBAR_SizeToHeight(REBAR_INFO *infoPtr, int height)
+{
+ int extra = height - infoPtr->calcSize.cy; /* may be negative */
+ BOOL fChanged = FALSE;
+ UINT uNumRows = infoPtr->uNumRows;
+ int i;
+
+ /* That's not exactly what Windows does but should be similar */
+
+ /* Pass one: break-up/glue rows */
+ if (extra > 0)
+ {
+ for (i = prev_band(infoPtr, infoPtr->uNumBands); i > 0; i = prev_band(infoPtr, i))
+ {
+ REBAR_BAND *lpBand = &infoPtr->bands[i];
+ int height = lpBand->rcBand.bottom - lpBand->rcBand.top;
+ int cyBreakExtra; /* additional cy for the rebar after a RBBS_BREAK on this band */
+
+ if (infoPtr->dwStyle & RBS_VARHEIGHT)
+ cyBreakExtra = lpBand->cyRowSoFar; /* 'height' => 'lpBand->cyRowSoFar' + 'height'*/
+ else
+ cyBreakExtra = height; /* 'height' => 'height' + 'height'*/
+ cyBreakExtra += SEP_WIDTH;
+
+ if (extra <= cyBreakExtra / 2)
+ break;
+
+ if (!(lpBand->fStyle & RBBS_BREAK))
+ {
+ TRACE("Adding break on band %d - extra %d -> %d\n", i, extra, extra - cyBreakExtra);
+ lpBand->fStyle |= RBBS_BREAK;
+ lpBand->fDraw |= NTF_INVALIDATE;
+ fChanged = TRUE;
+ extra -= cyBreakExtra;
+ uNumRows++;
+ /* temporary change for _SizeControlsToHeight. The true values will be computed in _Layout */
+ if (infoPtr->dwStyle & RBS_VARHEIGHT)
+ lpBand->rcBand.bottom = lpBand->rcBand.top + lpBand->lcy;
+ }
+ }
+ }
+ /* TODO: else if (extra < 0) { try to remove some RBBS_BREAKs } */
+
+ /* Pass two: increase/decrease control height */
+ if (infoPtr->dwStyle & RBS_VARHEIGHT)
+ {
+ int i = 0;
+ int iRow = 0;
+ while (i < infoPtr->uNumBands)
+ {
+ REBAR_BAND *lpBand = &infoPtr->bands[i];
+ int extraForRow = extra / (int)(uNumRows - iRow);
+ int rowEnd;
+
+ /* we can't use get_row_end_for_band as we might have added RBBS_BREAK in the first phase */
+ for (rowEnd = next_band(infoPtr, i); rowEnd < infoPtr->uNumBands; rowEnd = next_band(infoPtr, rowEnd))
+ if (infoPtr->bands[rowEnd].iRow != lpBand->iRow || (infoPtr->bands[rowEnd].fStyle & RBBS_BREAK))
+ break;
+
+ extra -= REBAR_SizeChildrenToHeight(infoPtr, i, rowEnd, extraForRow, &fChanged);
+ TRACE("extra = %d\n", extra);
+ i = rowEnd;
+ iRow++;
+ }
+ }
+ else
+ extra -= REBAR_SizeChildrenToHeight(infoPtr, 0, infoPtr->uNumBands, extra / infoPtr->uNumRows, &fChanged);
+
+ if (fChanged)
+ REBAR_Layout(infoPtr, NULL);
+}
+
static VOID
REBAR_ValidateBand (const REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
@@ -1485,17 +1598,10 @@ REBAR_ValidateBand (const REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
/* check if user overrode the header value */
if (!(lpBand->fStyle & RBBS_UNDOC_FIXEDHEADER))
lpBand->cxHeader = header;
-
+ lpBand->cyHeader = textheight;
/* Now compute minimum size of child window */
- lpBand->lcy = textheight;
- if (lpBand->hwndChild != NULL) {
- /* Set the .cy values for CHILDSIZE case */
- lpBand->lcy = max(lpBand->lcy, lpBand->cyChild + REBARSPACE(lpBand));
- TRACE("_CHILDSIZE\n");
- }
- else
- lpBand->lcy = max(lpBand->lcy, REBAR_NO_CHILD_HEIGHT);
+ update_min_band_height(infoPtr, lpBand); /* update lpBand->lcy from cyHeader and cyChild*/
lpBand->lcx = lpBand->cxMinChild + lpBand->cxHeader + REBAR_POST_CHILD;
if (lpBand->fStyle & RBBS_USECHEVRON && lpBand->cxMinChild < lpBand->cxIdeal)
@@ -1574,8 +1680,7 @@ REBAR_CommonSetupBand(HWND hwnd, const REBARBANDINFOW *lprbbi, REBAR_BAND *lpBan
lpBand->cyMaxChild = lprbbi->cyMaxChild;
lpBand->cyIntegral = lprbbi->cyIntegral;
- lpBand->cyChild = lpBand->cyMinChild;
- round_child_height(lpBand, lprbbi->cyChild); /* try to increase cyChild */
+ lpBand->cyChild = round_child_height(lpBand, lprbbi->cyChild); /* make (cyChild - cyMinChild) a multiple of cyIntergral */
}
else {
lpBand->cyChild = lpBand->cyMinChild;
@@ -2677,21 +2782,12 @@ static LRESULT
REBAR_SizeToRect (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
{
LPRECT lpRect = (LPRECT)lParam;
- RECT t1;
if (lpRect == NULL)
return FALSE;
TRACE("[%s]\n", wine_dbgstr_rect(lpRect));
-
- /* what is going on???? */
- GetWindowRect(infoPtr->hwndSelf, &t1);
- TRACE("window rect [%s]\n", wine_dbgstr_rect(&t1));
- GetClientRect(infoPtr->hwndSelf, &t1);
- TRACE("client rect [%s]\n", wine_dbgstr_rect(&t1));
-
- /* force full _Layout processing */
- REBAR_Layout(infoPtr, lpRect);
+ REBAR_SizeToHeight(infoPtr, get_rect_cy(infoPtr, lpRect));
InvalidateRect (infoPtr->hwndSelf, NULL, TRUE);
return TRUE;
}
More information about the wine-cvs
mailing list