📄 toolbar.c
字号:
static BOOL
TOOLBAR_IsValidBitmapIndex(TOOLBAR_INFO *infoPtr, INT index)
{
HIMAGELIST himl;
INT id = GETHIMLID(infoPtr, index);
INT iBitmap = GETIBITMAP(infoPtr, index);
if (((himl = GETDEFIMAGELIST(infoPtr, id)) &&
iBitmap >= 0 && iBitmap < ImageList_GetImageCount(himl)) ||
(index == I_IMAGECALLBACK))
return TRUE;
else
return FALSE;
}
static inline BOOL
TOOLBAR_IsValidImageList(TOOLBAR_INFO *infoPtr, INT index)
{
HIMAGELIST himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, index));
return (himl != NULL) && (ImageList_GetImageCount(himl) > 0);
}
/***********************************************************************
* TOOLBAR_GetImageListForDrawing
*
* This function validates the bitmap index (including I_IMAGECALLBACK
* functionality) and returns the corresponding image list.
*/
static HIMAGELIST
TOOLBAR_GetImageListForDrawing (TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, IMAGE_LIST_TYPE imagelist, INT * index)
{
HIMAGELIST himl;
if (!TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap)) {
if (btnPtr->iBitmap == I_IMAGENONE) return NULL;
ERR("bitmap for ID %d, index %d is not valid, number of bitmaps in imagelist: %d\n",
HIWORD(btnPtr->iBitmap), LOWORD(btnPtr->iBitmap), infoPtr->nNumBitmaps);
return NULL;
}
if ((*index = TOOLBAR_GetBitmapIndex(infoPtr, btnPtr)) < 0) {
if ((*index == I_IMAGECALLBACK) ||
(*index == I_IMAGENONE)) return NULL;
ERR("TBN_GETDISPINFO returned invalid index %d\n",
*index);
return NULL;
}
switch(imagelist)
{
case IMAGE_LIST_DEFAULT:
himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap));
break;
case IMAGE_LIST_HOT:
himl = GETHOTIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap));
break;
case IMAGE_LIST_DISABLED:
himl = GETDISIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap));
break;
default:
himl = NULL;
FIXME("Shouldn't reach here\n");
}
if (!himl)
TRACE("no image list\n");
return himl;
}
static void
TOOLBAR_DrawFlatSeparator (LPRECT lpRect, HDC hdc, TOOLBAR_INFO *infoPtr)
{
RECT myrect;
COLORREF oldcolor, newcolor;
myrect.left = (lpRect->left + lpRect->right) / 2 - 1;
myrect.right = myrect.left + 1;
myrect.top = lpRect->top + 2;
myrect.bottom = lpRect->bottom - 2;
newcolor = (infoPtr->clrBtnShadow == CLR_DEFAULT) ?
comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow;
oldcolor = SetBkColor (hdc, newcolor);
ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0);
myrect.left = myrect.right;
myrect.right = myrect.left + 1;
newcolor = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ?
comctl32_color.clrBtnHighlight : infoPtr->clrBtnHighlight;
SetBkColor (hdc, newcolor);
ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0);
SetBkColor (hdc, oldcolor);
}
/***********************************************************************
* TOOLBAR_DrawDDFlatSeparator
*
* This function draws the separator that was flagged as BTNS_DROPDOWN.
* In this case, the separator is a pixel high line of COLOR_BTNSHADOW,
* followed by a pixel high line of COLOR_BTNHIGHLIGHT. These separators
* are horizontal as opposed to the vertical separators for not dropdown
* type.
*
* FIXME: It is possible that the height of each line is really SM_CYBORDER.
*/
static void
TOOLBAR_DrawDDFlatSeparator (LPRECT lpRect, HDC hdc, TBUTTON_INFO *btnPtr, TOOLBAR_INFO *infoPtr)
{
RECT myrect;
COLORREF oldcolor, newcolor;
myrect.left = lpRect->left;
myrect.right = lpRect->right;
myrect.top = lpRect->top + (lpRect->bottom - lpRect->top - 2)/2;
myrect.bottom = myrect.top + 1;
InflateRect (&myrect, -2, 0);
TRACE("rect=(%d,%d)-(%d,%d)\n",
myrect.left, myrect.top, myrect.right, myrect.bottom);
newcolor = (infoPtr->clrBtnShadow == CLR_DEFAULT) ?
comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow;
oldcolor = SetBkColor (hdc, newcolor);
ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0);
myrect.top = myrect.bottom;
myrect.bottom = myrect.top + 1;
newcolor = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ?
comctl32_color.clrBtnHighlight : infoPtr->clrBtnHighlight;
SetBkColor (hdc, newcolor);
ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0);
SetBkColor (hdc, oldcolor);
}
static void
TOOLBAR_DrawArrow (HDC hdc, INT left, INT top, COLORREF clr)
{
INT x, y;
HPEN hPen, hOldPen;
if (!(hPen = CreatePen( PS_SOLID, 1, clr))) return;
hOldPen = SelectObject ( hdc, hPen );
x = left + 2;
y = top;
MoveToEx (hdc, x, y, NULL);
LineTo (hdc, x+5, y++); x++;
MoveToEx (hdc, x, y, NULL);
LineTo (hdc, x+3, y++); x++;
MoveToEx (hdc, x, y, NULL);
LineTo (hdc, x+1, y++);
SelectObject( hdc, hOldPen );
DeleteObject( hPen );
}
/*
* Draw the text string for this button.
* note: infoPtr->himlDis *SHOULD* be non-zero when infoPtr->himlDef
* is non-zero, so we can simply check himlDef to see if we have
* an image list
*/
static void
TOOLBAR_DrawString (TOOLBAR_INFO *infoPtr, RECT *rcText, LPWSTR lpText,
NMTBCUSTOMDRAW *tbcd, DWORD dwItemCDFlag)
{
HDC hdc = tbcd->nmcd.hdc;
HFONT hOldFont = 0;
COLORREF clrOld = 0;
COLORREF clrOldBk = 0;
int oldBkMode = 0;
UINT state = tbcd->nmcd.uItemState;
/* draw text */
if (lpText) {
TRACE("string=%s rect=(%d,%d)-(%d,%d)\n", debugstr_w(lpText),
rcText->left, rcText->top, rcText->right, rcText->bottom);
hOldFont = SelectObject (hdc, infoPtr->hFont);
if ((state & CDIS_HOT) && (dwItemCDFlag & TBCDRF_HILITEHOTTRACK )) {
clrOld = SetTextColor (hdc, tbcd->clrTextHighlight);
}
else if (state & CDIS_DISABLED) {
clrOld = SetTextColor (hdc, tbcd->clrBtnHighlight);
OffsetRect (rcText, 1, 1);
DrawTextW (hdc, lpText, -1, rcText, infoPtr->dwDTFlags);
SetTextColor (hdc, comctl32_color.clr3dShadow);
OffsetRect (rcText, -1, -1);
}
else if (state & CDIS_INDETERMINATE) {
clrOld = SetTextColor (hdc, comctl32_color.clr3dShadow);
}
else if ((state & CDIS_MARKED) && !(dwItemCDFlag & TBCDRF_NOMARK)) {
clrOld = SetTextColor (hdc, tbcd->clrTextHighlight);
clrOldBk = SetBkColor (hdc, tbcd->clrMark);
oldBkMode = SetBkMode (hdc, tbcd->nHLStringBkMode);
}
else {
clrOld = SetTextColor (hdc, tbcd->clrText);
}
DrawTextW (hdc, lpText, -1, rcText, infoPtr->dwDTFlags);
SetTextColor (hdc, clrOld);
if ((state & CDIS_MARKED) && !(dwItemCDFlag & TBCDRF_NOMARK))
{
SetBkColor (hdc, clrOldBk);
SetBkMode (hdc, oldBkMode);
}
SelectObject (hdc, hOldFont);
}
}
static void
TOOLBAR_DrawPattern (LPRECT lpRect, NMTBCUSTOMDRAW *tbcd)
{
HDC hdc = tbcd->nmcd.hdc;
HBRUSH hbr = SelectObject (hdc, tbcd->hbrMonoDither);
COLORREF clrTextOld;
COLORREF clrBkOld;
INT cx = lpRect->right - lpRect->left;
INT cy = lpRect->bottom - lpRect->top;
INT cxEdge = GetSystemMetrics(SM_CXEDGE);
INT cyEdge = GetSystemMetrics(SM_CYEDGE);
clrTextOld = SetTextColor(hdc, tbcd->clrBtnHighlight);
clrBkOld = SetBkColor(hdc, tbcd->clrBtnFace);
PatBlt (hdc, lpRect->left + cxEdge, lpRect->top + cyEdge,
cx - (2 * cxEdge), cy - (2 * cyEdge), PATCOPY);
SetBkColor(hdc, clrBkOld);
SetTextColor(hdc, clrTextOld);
SelectObject (hdc, hbr);
}
static void TOOLBAR_DrawMasked(HIMAGELIST himl, int index, HDC hdc, INT x, INT y, UINT draw_flags)
{
INT cx, cy;
HBITMAP hbmMask, hbmImage;
HDC hdcMask, hdcImage;
ImageList_GetIconSize(himl, &cx, &cy);
/* Create src image */
hdcImage = CreateCompatibleDC(hdc);
hbmImage = CreateCompatibleBitmap(hdc, cx, cy);
SelectObject(hdcImage, hbmImage);
ImageList_DrawEx(himl, index, hdcImage, 0, 0, cx, cy,
RGB(0xff, 0xff, 0xff), RGB(0,0,0), draw_flags);
/* Create Mask */
hdcMask = CreateCompatibleDC(0);
hbmMask = CreateBitmap(cx, cy, 1, 1, NULL);
SelectObject(hdcMask, hbmMask);
/* Remove the background and all white pixels */
ImageList_DrawEx(himl, index, hdcMask, 0, 0, cx, cy,
RGB(0xff, 0xff, 0xff), RGB(0,0,0), ILD_MASK);
SetBkColor(hdcImage, RGB(0xff, 0xff, 0xff));
BitBlt(hdcMask, 0, 0, cx, cy, hdcImage, 0, 0, NOTSRCERASE);
/* draw the new mask 'etched' to hdc */
SetBkColor(hdc, RGB(255, 255, 255));
SelectObject(hdc, GetSysColorBrush(COLOR_3DHILIGHT));
/* E20746 op code is (Dst ^ (Src & (Pat ^ Dst))) */
BitBlt(hdc, x + 1, y + 1, cx, cy, hdcMask, 0, 0, 0xE20746);
SelectObject(hdc, GetSysColorBrush(COLOR_3DSHADOW));
BitBlt(hdc, x, y, cx, cy, hdcMask, 0, 0, 0xE20746);
/* Cleanup */
DeleteObject(hbmImage);
DeleteDC(hdcImage);
DeleteObject (hbmMask);
DeleteDC(hdcMask);
}
static UINT
TOOLBAR_TranslateState(TBUTTON_INFO *btnPtr)
{
UINT retstate = 0;
retstate |= (btnPtr->fsState & TBSTATE_CHECKED) ? CDIS_CHECKED : 0;
retstate |= (btnPtr->fsState & TBSTATE_PRESSED) ? CDIS_SELECTED : 0;
retstate |= (btnPtr->fsState & TBSTATE_ENABLED) ? 0 : CDIS_DISABLED;
retstate |= (btnPtr->fsState & TBSTATE_MARKED ) ? CDIS_MARKED : 0;
retstate |= (btnPtr->bHot ) ? CDIS_HOT : 0;
retstate |= ((btnPtr->fsState & (TBSTATE_ENABLED|TBSTATE_INDETERMINATE)) == (TBSTATE_ENABLED|TBSTATE_INDETERMINATE)) ? CDIS_INDETERMINATE : 0;
/* NOTE: we don't set CDIS_GRAYED, CDIS_FOCUS, CDIS_DEFAULT */
return retstate;
}
/* draws the image on a toolbar button */
static void
TOOLBAR_DrawImage(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, INT left, INT top,
const NMTBCUSTOMDRAW *tbcd, DWORD dwItemCDFlag)
{
HIMAGELIST himl = NULL;
BOOL draw_masked = FALSE;
INT index;
INT offset = 0;
UINT draw_flags = ILD_TRANSPARENT;
if (tbcd->nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE))
{
himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DISABLED, &index);
if (!himl)
{
himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index);
draw_masked = TRUE;
}
}
else if (tbcd->nmcd.uItemState & CDIS_CHECKED ||
((tbcd->nmcd.uItemState & CDIS_HOT)
&& ((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf))))
{
/* if hot, attempt to draw with hot image list, if fails,
use default image list */
himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_HOT, &index);
if (!himl)
himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index);
}
else
himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index);
if (!himl)
return;
if (!(dwItemCDFlag & TBCDRF_NOOFFSET) &&
(tbcd->nmcd.uItemState & (CDIS_SELECTED | CDIS_CHECKED)))
offset = 1;
if (!(dwItemCDFlag & TBCDRF_NOMARK) &&
(tbcd->nmcd.uItemState & CDIS_MARKED))
draw_flags |= ILD_BLEND50;
TRACE("drawing index=%d, himl=%p, left=%d, top=%d, offset=%d\n",
index, himl, left, top, offset);
if (draw_masked)
TOOLBAR_DrawMasked (himl, index, tbcd->nmcd.hdc, left + offset, top + offset, draw_flags);
else
ImageList_Draw (himl, index, tbcd->nmcd.hdc, left + offset, top + offset, draw_flags);
}
/* draws a blank frame for a toolbar button */
static void
TOOLBAR_DrawFrame(const TOOLBAR_INFO *infoPtr, const NMTBCUSTOMDRAW *tbcd, DWORD dwItemCDFlag)
{
HDC hdc = tbcd->nmcd.hdc;
RECT rc = tbcd->nmcd.rc;
/* if the state is disabled or indeterminate then the button
* cannot have an interactive look like pressed or hot */
BOOL non_interactive_state = (tbcd->nmcd.uItemState & CDIS_DISABLED) ||
(tbcd->nmcd.uItemState & CDIS_INDETERMINATE);
BOOL pressed_look = !non_interactive_state &&
((tbcd->nmcd.uItemState & CDIS_SELECTED) ||
(tbcd->nmcd.uItemState & CDIS_CHECKED));
/* app don't want us to draw any edges */
if (dwItemCDFlag & TBCDRF_NOEDGES)
return;
if (infoPtr->dwStyle & TBSTYLE_FLAT)
{
if (pressed_look)
DrawEdge (hdc, &rc, BDR_SUNKENOUTER, BF_RECT);
else if ((tbcd->nmcd.uItemState & CDIS_HOT) && !non_interactive_state)
DrawEdge (hdc, &rc, BDR_RAISEDINNER, BF_RECT);
}
else
{
if (pressed_look)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -