📄 toolbar.c
字号:
* | centred +---------------+ | |
* |<--------------->| Text | | |
* | +---------------+ | |
* +-----------------------------------+ -
* <----------------------------------->
* pad.cx + max(nBitmapWidth, szText.cx)
*
* Without bitmaps (NULL imagelist or ImageList_GetImageCount() = 0):
*
* +---------------------------------------+ ^
* | ^ | |
* | | 2 + pad.cy / 2 | |
* | - | | szText.cy +
* | centred +-----------------+ | | pad.cy + 2
* |<--------------->| Text | | |
* | +-----------------+ | |
* | | |
* +---------------------------------------+ -
* <--------------------------------------->
* 2*cxedge + pad.cx + szText.cx
*
* Without text:
* As for with bitmaps, but with szText.cx zero.
*/
static inline SIZE TOOLBAR_MeasureButton(TOOLBAR_INFO *infoPtr, SIZE sizeString, BOOL bHasBitmap, BOOL bValidImageList)
{
SIZE sizeButton;
if (infoPtr->dwStyle & TBSTYLE_LIST)
{
/* set button height from bitmap / text height... */
sizeButton.cy = max((bHasBitmap ? infoPtr->nVBitmapHeight : 0),
sizeString.cy);
/* ... add on the necessary padding */
if (bValidImageList)
{
if (bHasBitmap)
sizeButton.cy += DEFPAD_CY;
else
sizeButton.cy += LISTPAD_CY;
}
else
sizeButton.cy += infoPtr->szPadding.cy;
/* calculate button width */
if (bHasBitmap)
{
sizeButton.cx = 2*GetSystemMetrics(SM_CXEDGE) +
infoPtr->nBitmapWidth + infoPtr->iListGap;
if (sizeString.cx > 0)
sizeButton.cx += sizeString.cx + infoPtr->szPadding.cx;
}
else
sizeButton.cx = sizeString.cx + infoPtr->szPadding.cx;
}
else
{
if (bHasBitmap)
{
sizeButton.cy = infoPtr->nVBitmapHeight + DEFPAD_CY;
if (sizeString.cy > 0)
sizeButton.cy += 1 + sizeString.cy;
sizeButton.cx = infoPtr->szPadding.cx +
max(sizeString.cx, infoPtr->nBitmapWidth);
}
else
{
sizeButton.cy = sizeString.cy + infoPtr->szPadding.cy +
NONLIST_NOTEXT_OFFSET;
sizeButton.cx = 2*GetSystemMetrics(SM_CXEDGE) +
infoPtr->szPadding.cx + sizeString.cx;
}
}
return sizeButton;
}
/***********************************************************************
* TOOLBAR_CalcToolbar
*
* This function calculates button and separator placement. It first
* calculates the button sizes, gets the toolbar window width and then
* calls TOOLBAR_WrapToolbar to determine which buttons we need to wrap
* on. It assigns a new location to each item and sends this location to
* the tooltip window if appropriate. Finally, it updates the rcBound
* rect and calculates the new required toolbar window height.
*/
static void
TOOLBAR_CalcToolbar (HWND hwnd)
{
TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
SIZE sizeString, sizeButton;
BOOL validImageList = FALSE;
TOOLBAR_CalcStrings (hwnd, &sizeString);
TOOLBAR_DumpToolbar (infoPtr, __LINE__);
if (TOOLBAR_IsValidImageList(infoPtr, 0))
validImageList = TRUE;
sizeButton = TOOLBAR_MeasureButton(infoPtr, sizeString, TRUE, validImageList);
infoPtr->nButtonWidth = sizeButton.cx;
infoPtr->nButtonHeight = sizeButton.cy;
infoPtr->iTopMargin = default_top_margin(infoPtr);
if ( infoPtr->cxMin >= 0 && infoPtr->nButtonWidth < infoPtr->cxMin )
infoPtr->nButtonWidth = infoPtr->cxMin;
if ( infoPtr->cxMax > 0 && infoPtr->nButtonWidth > infoPtr->cxMax )
infoPtr->nButtonWidth = infoPtr->cxMax;
TOOLBAR_LayoutToolbar(hwnd);
}
static void
TOOLBAR_LayoutToolbar(HWND hwnd)
{
TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
TBUTTON_INFO *btnPtr;
SIZE sizeButton;
INT i, nRows, nSepRows;
INT x, y, cx, cy;
BOOL bWrap;
BOOL validImageList = TOOLBAR_IsValidImageList(infoPtr, 0);
BOOL hasDropDownArrows = TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle);
TOOLBAR_WrapToolbar(hwnd, infoPtr->dwStyle);
x = infoPtr->nIndent;
y = infoPtr->iTopMargin;
cx = infoPtr->nButtonWidth;
cy = infoPtr->nButtonHeight;
nRows = nSepRows = 0;
infoPtr->rcBound.top = y;
infoPtr->rcBound.left = x;
infoPtr->rcBound.bottom = y + cy;
infoPtr->rcBound.right = x;
btnPtr = infoPtr->buttons;
TRACE("cy=%d\n", cy);
for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++ )
{
bWrap = FALSE;
if (btnPtr->fsState & TBSTATE_HIDDEN)
{
SetRectEmpty (&btnPtr->rect);
continue;
}
cy = infoPtr->nButtonHeight;
/* 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. */
if (btnPtr->fsStyle & BTNS_SEP) {
if (btnPtr->fsStyle & BTNS_DROPDOWN) {
cy = (btnPtr->iBitmap > 0) ?
btnPtr->iBitmap : SEPARATOR_WIDTH;
cx = infoPtr->nButtonWidth;
}
else
cx = (btnPtr->iBitmap > 0) ?
btnPtr->iBitmap : SEPARATOR_WIDTH;
}
else
{
if (btnPtr->cx)
cx = btnPtr->cx;
else if ((infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) ||
(btnPtr->fsStyle & BTNS_AUTOSIZE))
{
SIZE sz;
HDC hdc;
HFONT hOldFont;
hdc = GetDC (hwnd);
hOldFont = SelectObject (hdc, infoPtr->hFont);
TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz);
SelectObject (hdc, hOldFont);
ReleaseDC (hwnd, hdc);
sizeButton = TOOLBAR_MeasureButton(infoPtr, sz,
TOOLBAR_IsValidBitmapIndex(infoPtr, infoPtr->buttons[i].iBitmap),
validImageList);
cx = sizeButton.cx;
}
else
cx = infoPtr->nButtonWidth;
/* if size has been set manually then don't add on extra space
* for the drop down arrow */
if (!btnPtr->cx && hasDropDownArrows &&
((btnPtr->fsStyle & BTNS_DROPDOWN) || (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN)))
cx += DDARROW_WIDTH;
}
if (btnPtr->fsState & TBSTATE_WRAP )
bWrap = TRUE;
SetRect (&btnPtr->rect, x, y, x + cx, y + cy);
if (infoPtr->rcBound.left > x)
infoPtr->rcBound.left = x;
if (infoPtr->rcBound.right < x + cx)
infoPtr->rcBound.right = x + cx;
if (infoPtr->rcBound.bottom < y + cy)
infoPtr->rcBound.bottom = y + cy;
TOOLBAR_TooltipSetRect(infoPtr, btnPtr);
/* btnPtr->nRow is zero based. The space between the rows is */
/* also considered as a row. */
btnPtr->nRow = nRows + nSepRows;
TRACE("button %d style=%x, bWrap=%d, nRows=%d, nSepRows=%d, btnrow=%d, (%d,%d)-(%d,%d)\n",
i, btnPtr->fsStyle, bWrap, nRows, nSepRows, btnPtr->nRow,
x, y, x+cx, y+cy);
if( bWrap )
{
if ( !(btnPtr->fsStyle & BTNS_SEP) )
y += cy;
else
{
/* 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. */
if ( !(btnPtr->fsStyle & BTNS_DROPDOWN))
y += cy + ( (btnPtr->iBitmap > 0 ) ?
btnPtr->iBitmap : SEPARATOR_WIDTH) * 2 /3;
else
y += cy;
/* nSepRows is used to calculate the extra height follwoing */
/* the last row. */
nSepRows++;
}
x = infoPtr->nIndent;
/* Increment row number unless this is the last button */
/* and it has Wrap set. */
if (i != infoPtr->nNumButtons-1)
nRows++;
}
else
x += cx;
}
/* infoPtr->nRows is the number of rows on the toolbar */
infoPtr->nRows = nRows + nSepRows + 1;
TRACE("toolbar button width %d\n", infoPtr->nButtonWidth);
}
static INT
TOOLBAR_InternalHitTest (HWND hwnd, LPPOINT lpPt)
{
TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
TBUTTON_INFO *btnPtr;
INT i;
btnPtr = infoPtr->buttons;
for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) {
if (btnPtr->fsState & TBSTATE_HIDDEN)
continue;
if (btnPtr->fsStyle & BTNS_SEP) {
if (PtInRect (&btnPtr->rect, *lpPt)) {
TRACE(" ON SEPARATOR %d!\n", i);
return -i;
}
}
else {
if (PtInRect (&btnPtr->rect, *lpPt)) {
TRACE(" ON BUTTON %d!\n", i);
return i;
}
}
}
TRACE(" NOWHERE!\n");
return TOOLBAR_NOWHERE;
}
static INT
TOOLBAR_GetButtonIndex (TOOLBAR_INFO *infoPtr, INT idCommand, BOOL CommandIsIndex)
{
TBUTTON_INFO *btnPtr;
INT i;
if (CommandIsIndex) {
TRACE("command is really index command=%d\n", idCommand);
if (idCommand >= infoPtr->nNumButtons) return -1;
return idCommand;
}
btnPtr = infoPtr->buttons;
for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) {
if (btnPtr->idCommand == idCommand) {
TRACE("command=%d index=%d\n", idCommand, i);
return i;
}
}
TRACE("no index found for command=%d\n", idCommand);
return -1;
}
static INT
TOOLBAR_GetCheckedGroupButtonIndex (TOOLBAR_INFO *infoPtr, INT nIndex)
{
TBUTTON_INFO *btnPtr;
INT nRunIndex;
if ((nIndex < 0) || (nIndex > infoPtr->nNumButtons))
return -1;
/* check index button */
btnPtr = &infoPtr->buttons[nIndex];
if ((btnPtr->fsStyle & BTNS_CHECKGROUP) == BTNS_CHECKGROUP) {
if (btnPtr->fsState & TBSTATE_CHECKED)
return nIndex;
}
/* check previous buttons */
nRunIndex = nIndex - 1;
while (nRunIndex >= 0) {
btnPtr = &infoPtr->buttons[nRunIndex];
if ((btnPtr->fsStyle & BTNS_GROUP) == BTNS_GROUP) {
if (btnPtr->fsState & TBSTATE_CHECKED)
return nRunIndex;
}
else
break;
nRunIndex--;
}
/* check next buttons */
nRunIndex = nIndex + 1;
while (nRunIndex < infoPtr->nNumButtons) {
btnPtr = &infoPtr->buttons[nRunIndex];
if ((btnPtr->fsStyle & BTNS_GROUP) == BTNS_GROUP) {
if (btnPtr->fsState & TBSTATE_CHECKED)
return nRunIndex;
}
else
break;
nRunIndex++;
}
return -1;
}
static VOID
TOOLBAR_RelayEvent (HWND hwndTip, HWND hwndMsg, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
MSG msg;
msg.hwnd = hwndMsg;
msg.message = uMsg;
msg.wParam = wParam;
msg.lParam = lParam;
msg.time = GetMessageTime ();
msg.pt.x = (short)LOWORD(GetMessagePos ());
msg.pt.y = (short)HIWORD(GetMessagePos ());
SendMessageW (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
}
static void
TOOLBAR_TooltipAddTool(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *button)
{
if (infoPtr->hwndToolTi
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -