📄 rebar.c
字号:
* 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(const 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(const 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(const 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(const 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(const 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, const RECT *lpRect)
{
REBAR_BAND *lpBand;
RECT rcAdj;
SIZE oldSize;
INT adjcx, adjcy, i;
INT rowstart = 0;
INT row = 0;
INT xMin, yPos;
INT cyTarget;
const INT yInit = 0;
cyTarget = 0;
if (lpRect) {
rcAdj = *lpRect;
cyTarget = get_rect_cy(infoPtr, lpRect);
} else if (infoPtr->dwStyle & (CCS_NORESIZE | CCS_NOPARENTALIGN) || GetParent(infoPtr->hwndSelf) == NULL)
GetClientRect(infoPtr->hwndSelf, &rcAdj);
else
GetClientRect(GetParent(infoPtr->hwndSelf), &rcAdj);
TRACE("adjustment rect is (%d,%d)-(%d,%d)\n", rcAdj.left, rcAdj.top, rcAdj.right, rcAdj.bottom);
adjcx = get_rect_cx(infoPtr, &rcAdj);
adjcy = get_rect_cy(infoPtr, &rcAdj);
if (infoPtr->uNumBands == 0) {
TRACE("No bands - setting size to (0,%d), vert: %lx\n", adjcx, infoPtr->dwStyle & CCS_VERT);
infoPtr->calcSize.cx = adjcx;
/* the calcSize.cy won't change for a 0 band rebar */
infoPtr->uNumRows = 0;
REBAR_ForceResize(infoPtr);
return;
}
yPos = yInit;
xMin = 0;
/* divide rows */
i = 0;
for (i = 0; i < infoPtr->uNumBands; i++)
{
lpBand = &infoPtr->bands[i];
if (HIDDENBAND(lpBand)) continue;
if (i > rowstart && (lpBand->fStyle & RBBS_BREAK || xMin + lpBand->lcx > adjcx)) {
TRACE("%s break on band %d\n", (lpBand->fStyle & RBBS_BREAK ? "Hard" : "Soft"), i - 1);
REBAR_LayoutRow(infoPtr, rowstart, i, adjcx, &row, &yPos);
rowstart = i;
xMin = 0;
}
else
xMin += SEP_WIDTH;
xMin += lpBand->lcx;
}
REBAR_LayoutRow(infoPtr, rowstart, infoPtr->uNumBands, adjcx, &row, &yPos);
if (!(infoPtr->dwStyle & RBS_VARHEIGHT))
yPos = REBAR_SetBandsHeight(infoPtr, 0, infoPtr->uNumBands, yInit);
infoPtr->uNumRows = row;
if (infoPtr->dwStyle & CCS_VERT)
REBAR_CalcVertBand(infoPtr, 0, infoPtr->uNumBands);
else
REBAR_CalcHorzBand(infoPtr, 0, infoPtr->uNumBands);
/* now compute size of Rebar itself */
oldSize = infoPtr->calcSize;
infoPtr->calcSize.cx = adjcx;
infoPtr->calcSize.cy = yPos;
TRACE("calcsize size=(%d, %d), origheight=(%d,%d)\n",
infoPtr->calcSize.cx, infoPtr->calcSize.cy,
oldSize.cx, oldSize.cy);
REBAR_DumpBand (infoPtr);
REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands);
REBAR_ForceResize (infoPtr);
/* note: after a RBN_HEIGHTCHANGE native sends once again all the RBN_CHILDSIZE
* and does another ForceResize */
if (oldSize.cy != infoPtr->calcSize.cy)
{
NMHDR heightchange;
REBAR_Notify(&heightchange, infoPtr, RBN_HEIGHTCHANGE);
}
}
static VOID
REBAR_ValidateBand (const REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
/* Function: This routine evaluates the band specs supplied */
/* by the user and updates the following 5 fields in */
/* the internal band structure: cxHeader, lcx, lcy, hcx, hcy*/
{
UINT header=0;
UINT textheight=0;
UINT i, nonfixed;
REBAR_BAND *tBand;
lpBand->fStatus = 0;
lpBand->lcx = 0;
lpBand->lcy = 0;
/* Data coming in from users into the cx... and cy... fields */
/* may be bad, just garbage, because the user never clears */
/* the fields. RB_{SET|INSERT}BAND{A|W} just passes the data */
/* along if the fields exist in the input area. Here we must */
/* determine if the data is valid. I have no idea how MS does */
/* the validation, but it does because the RB_GETBANDINFO */
/* returns a 0 when I know the sample program passed in an */
/* address. Here I will use the algorithm that if the value */
/* is greater than 65535 then it is bad and replace it with */
/* a zero. Feel free to improve the algorithm. - GA 12/2000 */
if (lpBand->cxMinChild > 65535) lpBand->cxMinChild = 0;
if (lpBand->cyMinChild > 65535) lpBand->cyMinChild = 0;
if (lpBand->cx > 65535) lpBand->cx = 0;
if (lpBand->cyChild > 65535) lpBand->cyChild = 0;
if (lpBand->cyIntegral > 65535) lpBand->cyIntegral = 0;
if (lpBand->cxIdeal > 65535) lpBand->cxIdeal = 0;
if (lpBand->cxHeader > 65535) lpBand->cxHeader = 0;
/* TODO : we could try return to the caller if a value changed so that */
/* a REBAR_Layout is needed. Till now the caller should call it */
/* it always (we should also check what native does) */
/* Header is where the image, text and gripper exist */
/* in the band and precede the child window. */
/* count number of non-FIXEDSIZE and non-Hidden bands */
nonfixed = 0;
for (i=0; i<infoPtr->uNumBands; i++){
tBand = &infoPtr->bands[i];
if (!HIDDENBAND(tBand) && !(tBand->fStyle & RBBS_FIXEDSIZE))
nonfixed++;
}
/* calculate gripper rectangle */
if ( (!(lpBand->fStyle & RBBS_NOGRIPPER)) &&
( (lpBand->fStyle & RBBS_GRIPPERALWAYS) ||
( !(lpBand->fStyle & RBBS_FIXEDSIZE) && (nonfixed > 1)))
) {
lpBand->fStatus |= HAS_GRIPPER;
if (infoPtr->dwStyle & CCS_VERT)
if (infoPtr->dwStyle & RBS_VERTICALGRIPPER)
header += (GRIPPER_HEIGHT + REBAR_PRE_GRIPPER);
else
header += (GRIPPER_WIDTH + REBAR_PRE_GRIPPER);
else
header += (REBAR_PRE_GRIPPER + GRIPPER_WIDTH);
/* Always have 4 pixels before anything else */
header += REBAR_ALWAYS_SPACE;
}
/* image is visible */
if ((lpBand->fMask & RBBIM_IMAGE) && (infoPtr->himl)) {
lpBand->fStatus |= HAS_IMAGE;
if (infoPtr->dwStyle & CCS_VERT) {
header += (infoPtr->imageSize.cy + REBAR_POST_IMAGE);
lpBand->lcy = infoPtr->imageSize.cx + 2;
}
else {
header += (infoPtr->imageSize.cx + REBAR_POST_IMAGE);
lpBand->lcy = infoPtr->imageSize.cy + 2;
}
}
/* text is visible */
if ((lpBand->fMask & RBBIM_TEXT) && (lpBand->lpText) &&
!(lpBand->fStyle & RBBS_HIDETITLE)) {
HDC hdc = GetDC (0);
HFONT hOldFont = SelectObject (hdc, infoPtr->hFont);
SIZE size;
lpBand->fStatus |= HAS_TEXT;
GetTextExtentPoint32W (hdc, lpBand->lpText,
lstrlenW (lpBand->lpText), &size);
header += ((infoPtr->dwStyle & CCS_VERT) ? (size.cy + REBAR_POST_TEXT) : (size.cx + REBAR_POST_TEXT));
textheight = (infoPtr->dwStyle & CCS_VERT) ? 0 : size.cy;
SelectObject (hdc, hOldFont);
ReleaseDC (0, hdc);
}
/* if no gripper but either image or text, then leave space */
if ((lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) &&
!(lpBand->fStatus & HAS_GRIPPER)) {
header += REBAR_ALWAYS_SPACE;
}
/* check if user overrode the header value */
if (!(lpBand->fStyle & RBBS_UNDOC_FIXEDHEADER))
lpBand->cxHeader = header;
/* 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);
lpBand->lcx = lpBand->cxMinChild + lpBand->cxHeader + REBAR_POST_CHILD;
if (lpBand->fStyle & RBBS_USECHEVRON && lpBand->cxMinChild < lpBand->cxIdeal)
lpBand->lcx += CHEVRON_WIDTH;
}
static BOOL
REBAR_CommonSetupBand(HWND hwnd, const REBARBANDINFOW *lprbbi, REBAR_BAND *lpBand)
/* Function: This routine copies the supplied values from */
/* user input (lprbbi) to the internal band structure. */
/* It returns true if something changed and false if not. */
{
BOOL bChanged = FALSE;
lpBand->fMask |= lprbbi->fMask;
if( (lprbbi->fMask & RBBIM_STYLE) &&
(lpBand->fStyle != lprbbi->fStyle ) )
{
lpBand->fStyle = lprbbi->fStyle;
bChanged = TRUE;
}
if( (lprbbi->fMask & RBBIM_COLORS) &&
( ( lpBand->clrFore != lprbbi->clrFore ) ||
( lpBand->clrBack != lprbbi->clrBack ) ) )
{
lpBand->clrFore = lprbbi->clrFore;
lpBand->clrBack = lprbbi->clrBack;
bChanged = TRUE;
}
if( (lprbbi->fMask & RBBIM_IMAGE) &&
( lpBand->iImage != lprbbi->iImage ) )
{
lpBand->iImage = lprbbi->iImage;
bChanged = TRUE;
}
if( (lprbbi->fMask & RBBIM_CHILD) &&
(lprbbi->hwndChild != lpBand->hwndChild ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -