toolbar.c

来自「一个类似windows」· C语言 代码 · 共 1,915 行 · 第 1/5 页

C
1,915
字号
* |                 +-----------------+   | |
* |                                       | |
* +---------------------------------------+ -
* <--------------------------------------->
*          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->nBitmapHeight : 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->nBitmapHeight + 1 +
                sizeString.cy + DEFPAD_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);
    DWORD dwStyle = infoPtr->dwStyle;
    TBUTTON_INFO *btnPtr;
    INT i, nRows, nSepRows;
    INT x, y, cx, cy;
    SIZE  sizeString, sizeButton;
    BOOL bWrap;
    BOOL validImageList = FALSE;
    BOOL hasDropDownArrows = TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle);

    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;

    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_WrapToolbar( hwnd, dwStyle );

    x  = infoPtr->nIndent;
    if (infoPtr->dwStyle & TBSTYLE_FLAT)
        y = 0;
    else
        y = TOP_BORDER;

    /* from above, minimum is a button, and possible text */
    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;

	/* Set the toolTip only for non-hidden, non-separator button */
	if (infoPtr->hwndToolTip && !(btnPtr->fsStyle & BTNS_SEP ))
	{
	    TTTOOLINFOW ti;

	    ZeroMemory (&ti, sizeof(ti));
	    ti.cbSize = sizeof(ti);
	    ti.hwnd = hwnd;
	    ti.uId = btnPtr->idCommand;
	    ti.rect = btnPtr->rect;
	    SendMessageW (infoPtr->hwndToolTip, TTM_NEWTOOLRECTW,
			    0, (LPARAM)&ti);
	}

	/* 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 = LOWORD(GetMessagePos ());
    msg.pt.y = HIWORD(GetMessagePos ());

    SendMessageW (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
}

/* keeps available button list box sorted by button id */
static void TOOLBAR_Cust_InsertAvailButton(HWND hwnd, PCUSTOMBUTTON btnInfoNew)
{
    int i;
    int count;
    PCUSTOMBUTTON btnInfo;
    HWND hwndAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX);

    TRACE("button %s, idCommand %d\n", debugstr_w(btnInfoNew->text), btnInfoNew->btn.idCommand);

    count = SendMessageW(hwndAvail, LB_GETCOUNT, 0, 0);

    /* position 0 is always separator */
    for (i = 1; i < count; i++)
    {
        btnInfo = (PCUSTOMBUTTON)Se

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?