📄 toolbar.c
字号:
if (dwBaseCustDraw & CDRF_NOTIFYPOSTPAINT)
{
ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
tbcd.nmcd.dwDrawStage = CDDS_POSTPAINT;
tbcd.nmcd.hdc = hdc;
tbcd.nmcd.rc = ps->rcPaint;
ntfret = TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW);
}
}
/***********************************************************************
* TOOLBAR_MeasureString
*
* This function gets the width and height of a string in pixels. This
* is done first by using GetTextExtentPoint to get the basic width
* and height. The DrawText is called with DT_CALCRECT to get the exact
* width. The reason is because the text may have more than one "&" (or
* prefix characters as M$ likes to call them). The prefix character
* indicates where the underline goes, except for the string "&&" which
* is reduced to a single "&". GetTextExtentPoint does not process these
* only DrawText does. Note that the BTNS_NOPREFIX is handled here.
*/
static void
TOOLBAR_MeasureString(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr,
HDC hdc, LPSIZE lpSize)
{
RECT myrect;
lpSize->cx = 0;
lpSize->cy = 0;
if (infoPtr->nMaxTextRows > 0 &&
!(btnPtr->fsState & TBSTATE_HIDDEN) &&
(!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) ||
(btnPtr->fsStyle & BTNS_SHOWTEXT)) )
{
LPWSTR lpText = TOOLBAR_GetText(infoPtr, btnPtr);
if(lpText != NULL) {
/* first get size of all the text */
GetTextExtentPoint32W (hdc, lpText, strlenW (lpText), lpSize);
/* feed above size into the rectangle for DrawText */
myrect.left = myrect.top = 0;
myrect.right = lpSize->cx;
myrect.bottom = lpSize->cy;
/* Use DrawText to get true size as drawn (less pesky "&") */
DrawTextW (hdc, lpText, -1, &myrect, DT_VCENTER | DT_SINGLELINE |
DT_CALCRECT | ((btnPtr->fsStyle & BTNS_NOPREFIX) ?
DT_NOPREFIX : 0));
/* feed back to caller */
lpSize->cx = myrect.right;
lpSize->cy = myrect.bottom;
}
}
TRACE("string size %d x %d!\n", lpSize->cx, lpSize->cy);
}
/***********************************************************************
* TOOLBAR_CalcStrings
*
* This function walks through each string and measures it and returns
* the largest height and width to caller.
*/
static void
TOOLBAR_CalcStrings (HWND hwnd, LPSIZE lpSize)
{
TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
TBUTTON_INFO *btnPtr;
INT i;
SIZE sz;
HDC hdc;
HFONT hOldFont;
lpSize->cx = 0;
lpSize->cy = 0;
if (infoPtr->nMaxTextRows == 0)
return;
hdc = GetDC (hwnd);
hOldFont = SelectObject (hdc, infoPtr->hFont);
if (infoPtr->nNumButtons == 0 && infoPtr->nNumStrings > 0)
{
TEXTMETRICW tm;
GetTextMetricsW(hdc, &tm);
lpSize->cy = tm.tmHeight;
}
btnPtr = infoPtr->buttons;
for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) {
if(TOOLBAR_HasText(infoPtr, btnPtr))
{
TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz);
if (sz.cx > lpSize->cx)
lpSize->cx = sz.cx;
if (sz.cy > lpSize->cy)
lpSize->cy = sz.cy;
}
}
SelectObject (hdc, hOldFont);
ReleaseDC (hwnd, hdc);
TRACE("max string size %d x %d!\n", lpSize->cx, lpSize->cy);
}
/***********************************************************************
* TOOLBAR_WrapToolbar
*
* This function walks through the buttons and separators in the
* toolbar, and sets the TBSTATE_WRAP flag only on those items where
* wrapping should occur based on the width of the toolbar window.
* It does *not* calculate button placement itself. That task
* takes place in TOOLBAR_CalcToolbar. If the program wants to manage
* the toolbar wrapping on its own, it can use the TBSTYLE_WRAPABLE
* flag, and set the TBSTATE_WRAP flags manually on the appropriate items.
*
* Note: TBSTYLE_WRAPABLE or TBSTYLE_EX_UNDOC1 can be used also to allow
* vertical toolbar lists.
*/
static void
TOOLBAR_WrapToolbar( HWND hwnd, DWORD dwStyle )
{
TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
TBUTTON_INFO *btnPtr;
INT x, cx, i, j;
RECT rc;
BOOL bWrap, bButtonWrap;
/* When the toolbar window style is not TBSTYLE_WRAPABLE, */
/* no layout is necessary. Applications may use this style */
/* to perform their own layout on the toolbar. */
if( !(dwStyle & TBSTYLE_WRAPABLE) &&
!(infoPtr->dwExStyle & TBSTYLE_EX_UNDOC1) ) return;
btnPtr = infoPtr->buttons;
x = infoPtr->nIndent;
if (GetParent(hwnd))
{
/* this can get the parents width, to know how far we can extend
* this toolbar. We cannot use its height, as there may be multiple
* toolbars in a rebar control
*/
GetClientRect( GetParent(hwnd), &rc );
infoPtr->nWidth = rc.right - rc.left;
}
else
{
GetWindowRect( hwnd, &rc );
infoPtr->nWidth = rc.right - rc.left;
}
bButtonWrap = FALSE;
TRACE("start ButtonWidth=%d, BitmapWidth=%d, nWidth=%d, nIndent=%d\n",
infoPtr->nButtonWidth, infoPtr->nBitmapWidth, infoPtr->nWidth,
infoPtr->nIndent);
for (i = 0; i < infoPtr->nNumButtons; i++ )
{
bWrap = FALSE;
btnPtr[i].fsState &= ~TBSTATE_WRAP;
if (btnPtr[i].fsState & TBSTATE_HIDDEN)
continue;
/* UNDOCUMENTED: If a separator has a non zero bitmap index, */
/* it is the actual width of the separator. This is used for */
/* custom controls in toolbars. */
/* */
/* BTNS_DROPDOWN separators are treated as buttons for */
/* width. - GA 8/01 */
if ((btnPtr[i].fsStyle & BTNS_SEP) &&
!(btnPtr[i].fsStyle & BTNS_DROPDOWN))
cx = (btnPtr[i].iBitmap > 0) ?
btnPtr[i].iBitmap : SEPARATOR_WIDTH;
else
cx = infoPtr->nButtonWidth;
/* Two or more adjacent separators form a separator group. */
/* The first separator in a group should be wrapped to the */
/* next row if the previous wrapping is on a button. */
if( bButtonWrap &&
(btnPtr[i].fsStyle & BTNS_SEP) &&
(i + 1 < infoPtr->nNumButtons ) &&
(btnPtr[i + 1].fsStyle & BTNS_SEP) )
{
TRACE("wrap point 1 btn %d style %02x\n", i, btnPtr[i].fsStyle);
btnPtr[i].fsState |= TBSTATE_WRAP;
x = infoPtr->nIndent;
i++;
bButtonWrap = FALSE;
continue;
}
/* The layout makes sure the bitmap is visible, but not the button. */
/* Test added to also wrap after a button that starts a row but */
/* is bigger than the area. - GA 8/01 */
if (( x + cx - (infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2
> infoPtr->nWidth ) ||
((x == infoPtr->nIndent) && (cx > infoPtr->nWidth)))
{
BOOL bFound = FALSE;
/* If the current button is a separator and not hidden, */
/* go to the next until it reaches a non separator. */
/* Wrap the last separator if it is before a button. */
while( ( ((btnPtr[i].fsStyle & BTNS_SEP) &&
!(btnPtr[i].fsStyle & BTNS_DROPDOWN)) ||
(btnPtr[i].fsState & TBSTATE_HIDDEN) ) &&
i < infoPtr->nNumButtons )
{
i++;
bFound = TRUE;
}
if( bFound && i < infoPtr->nNumButtons )
{
i--;
TRACE("wrap point 2 btn %d style %02x, x=%d, cx=%d\n",
i, btnPtr[i].fsStyle, x, cx);
btnPtr[i].fsState |= TBSTATE_WRAP;
x = infoPtr->nIndent;
bButtonWrap = FALSE;
continue;
}
else if ( i >= infoPtr->nNumButtons)
break;
/* If the current button is not a separator, find the last */
/* separator and wrap it. */
for ( j = i - 1; j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--)
{
if ((btnPtr[j].fsStyle & BTNS_SEP) &&
!(btnPtr[j].fsState & TBSTATE_HIDDEN))
{
bFound = TRUE;
i = j;
TRACE("wrap point 3 btn %d style %02x, x=%d, cx=%d\n",
i, btnPtr[i].fsStyle, x, cx);
x = infoPtr->nIndent;
btnPtr[j].fsState |= TBSTATE_WRAP;
bButtonWrap = FALSE;
break;
}
}
/* If no separator available for wrapping, wrap one of */
/* non-hidden previous button. */
if (!bFound)
{
for ( j = i - 1;
j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--)
{
if (btnPtr[j].fsState & TBSTATE_HIDDEN)
continue;
bFound = TRUE;
i = j;
TRACE("wrap point 4 btn %d style %02x, x=%d, cx=%d\n",
i, btnPtr[i].fsStyle, x, cx);
x = infoPtr->nIndent;
btnPtr[j].fsState |= TBSTATE_WRAP;
bButtonWrap = TRUE;
break;
}
}
/* If all above failed, wrap the current button. */
if (!bFound)
{
TRACE("wrap point 5 btn %d style %02x, x=%d, cx=%d\n",
i, btnPtr[i].fsStyle, x, cx);
btnPtr[i].fsState |= TBSTATE_WRAP;
bFound = TRUE;
x = infoPtr->nIndent;
if (btnPtr[i].fsStyle & BTNS_SEP )
bButtonWrap = FALSE;
else
bButtonWrap = TRUE;
}
}
else {
TRACE("wrap point 6 btn %d style %02x, x=%d, cx=%d\n",
i, btnPtr[i].fsStyle, x, cx);
x += cx;
}
}
}
/***********************************************************************
* TOOLBAR_MeasureButton
*
* Calculates the width and height required for a button. Used in
* TOOLBAR_CalcToolbar to set the all-button width and height and also for
* the width of buttons that are autosized.
*
* Note that it would have been rather elegant to use one piece of code for
* both the laying out of the toolbar and for controlling where button parts
* are drawn, but the native control has inconsistencies between the two that
* prevent this from being effectively. These inconsistencies can be seen as
* artefacts where parts of the button appear outside of the bounding button
* rectangle.
*
* There are several cases for the calculation of the button dimensions and
* button part positioning:
*
* List
* ====
*
* With Bitmap:
*
* +--------------------------------------------------------+ ^
* | ^ ^ | |
* | | pad.cy / 2 | centred | |
* | pad.cx/2 + cxedge +--------------+ +------------+ | | DEFPAD_CY +
* |<----------------->| nBitmapWidth | | Text | | | max(nBitmapHeight, szText.cy)
* | |<------------>| | | | |
* | +--------------+ +------------+ | |
* |<-------------------------------------->| | |
* | cxedge + iListGap + nBitmapWidth + 2 |<-----------> | |
* | szText.cx | |
* +--------------------------------------------------------+ -
* <-------------------------------------------------------->
* 2*cxedge + nBitmapWidth + iListGap + szText.cx + pad.cx
*
* Without Bitmap (I_IMAGENONE):
*
* +-----------------------------------+ ^
* | ^ | |
* | | centred | | LISTPAD_CY +
* | +------------+ | | szText.cy
* | | Text | | |
* | | | | |
* | +------------+ | |
* |<----------------->| | |
* | cxedge |<-----------> | |
* | szText.cx | |
* +-----------------------------------+ -
* <----------------------------------->
* szText.cx + pad.cx
*
* Without text:
*
* +--------------------------------------+ ^
* | ^ | |
* | | padding.cy/2 | | DEFPAD_CY +
* | +------------+ | | nBitmapHeight
* | | Bitmap | | |
* | | | | |
* | +------------+ | |
* |<------------------->| | |
* | cxedge + iListGap/2 |<-----------> | |
* | nBitmapWidth | |
* +--------------------------------------+ -
* <-------------------------------------->
* 2*cxedge + nBitmapWidth + iListGap
*
* Non-List
* ========
*
* With bitmap:
*
* +-----------------------------------+ ^
* | ^ | |
* | | pad.cy / 2 | | nBitmapHeight +
* | - | | szText.cy +
* | +------------+ | | DEFPAD_CY + 1
* | centred | Bitmap | | |
* |<----------------->| | | |
* | +------------+ | |
* | ^ | |
* | 1 | | |
* | - | |
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -