📄 toolbar.c
字号:
/*
* Toolbar control
*
* Copyright 1998,1999 Eric Kohl
* Copyright 2000 Eric Kohl for CodeWeavers
* Copyright 2004 Robert Shearman
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* NOTES
*
* This code was audited for completeness against the documented features
* of Comctl32.dll version 6.0 on Mar. 14, 2004, by Robert Shearman.
*
* Unless otherwise noted, we believe this code to be complete, as per
* the specification mentioned above.
* If you discover missing features or bugs please note them below.
*
* TODO:
* - Styles:
* - TBSTYLE_REGISTERDROP
* - TBSTYLE_EX_DOUBLEBUFFER
* - Messages:
* - TB_GETMETRICS
* - TB_GETOBJECT
* - TB_INSERTMARKHITTEST
* - TB_SAVERESTORE
* - TB_SETMETRICS
* - WM_WININICHANGE
* - Notifications:
* - NM_CHAR
* - TBN_GETOBJECT
* - TBN_SAVE
* - Button wrapping (under construction).
* - Fix TB_SETROWS.
* - iListGap custom draw support.
*
* Testing:
* - Run tests using Waite Group Windows95 API Bible Volume 2.
* The second cdrom contains executables addstr.exe, btncount.exe,
* btnstate.exe, butstrsz.exe, chkbtn.exe, chngbmp.exe, customiz.exe,
* enablebtn.exe, getbmp.exe, getbtn.exe, getflags.exe, hidebtn.exe,
* indetbtn.exe, insbtn.exe, pressbtn.exe, setbtnsz.exe, setcmdid.exe,
* setparnt.exe, setrows.exe, toolwnd.exe.
* - Microsoft's controlspy examples.
* - Charles Petzold's 'Programming Windows': gadgets.exe
*
* Differences between MSDN and actual native control operation:
* 1. MSDN says: "TBSTYLE_LIST: Creates a flat toolbar with button text
* to the right of the bitmap. Otherwise, this style is
* identical to TBSTYLE_FLAT."
* As implemented by both v4.71 and v5.80 of the native COMCTL32.DLL
* you can create a TBSTYLE_LIST without TBSTYLE_FLAT and the result
* is non-flat non-transparent buttons. Therefore TBSTYLE_LIST does
* *not* imply TBSTYLE_FLAT as documented. (GA 8/2001)
*
*/
#include <stdarg.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "wingdi.h"
#include "winuser.h"
#include "wine/unicode.h"
#include "winnls.h"
#include "commctrl.h"
#include "comctl32.h"
#include "uxtheme.h"
#include "tmschema.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(toolbar);
static HCURSOR hCursorDrag = NULL;
typedef struct
{
INT iBitmap;
INT idCommand;
BYTE fsState;
BYTE fsStyle;
BYTE bHot;
BYTE bDropDownPressed;
DWORD_PTR dwData;
INT_PTR iString;
INT nRow;
RECT rect;
INT cx; /* manually set size */
} TBUTTON_INFO;
typedef struct
{
UINT nButtons;
HINSTANCE hInst;
UINT nID;
} TBITMAP_INFO;
typedef struct
{
HIMAGELIST himl;
INT id;
} IMLENTRY, *PIMLENTRY;
typedef struct
{
DWORD dwStructSize; /* size of TBBUTTON struct */
INT nWidth; /* width of the toolbar */
RECT client_rect;
RECT rcBound; /* bounding rectangle */
INT nButtonHeight;
INT nButtonWidth;
INT nBitmapHeight;
INT nBitmapWidth;
INT nIndent;
INT nRows; /* number of button rows */
INT nMaxTextRows; /* maximum number of text rows */
INT cxMin; /* minimum button width */
INT cxMax; /* maximum button width */
INT nNumButtons; /* number of buttons */
INT nNumBitmaps; /* number of bitmaps */
INT nNumStrings; /* number of strings */
INT nNumBitmapInfos;
INT nButtonDown; /* toolbar button being pressed or -1 if none */
INT nButtonDrag; /* toolbar button being dragged or -1 if none */
INT nOldHit;
INT nHotItem; /* index of the "hot" item */
SIZE szPadding; /* padding values around button */
INT iTopMargin; /* the top margin */
INT iListGap; /* default gap between text and image for toolbar with list style */
HFONT hDefaultFont;
HFONT hFont; /* text font */
HIMAGELIST himlInt; /* image list created internally */
PIMLENTRY *himlDef; /* default image list array */
INT cimlDef; /* default image list array count */
PIMLENTRY *himlHot; /* hot image list array */
INT cimlHot; /* hot image list array count */
PIMLENTRY *himlDis; /* disabled image list array */
INT cimlDis; /* disabled image list array count */
HWND hwndToolTip; /* handle to tool tip control */
HWND hwndNotify; /* handle to the window that gets notifications */
HWND hwndSelf; /* my own handle */
BOOL bAnchor; /* anchor highlight enabled */
BOOL bDoRedraw; /* Redraw status */
BOOL bDragOutSent; /* has TBN_DRAGOUT notification been sent for this drag? */
BOOL bUnicode; /* Notifications are ASCII (FALSE) or Unicode (TRUE)? */
BOOL bCaptured; /* mouse captured? */
DWORD dwStyle; /* regular toolbar style */
DWORD dwExStyle; /* extended toolbar style */
DWORD dwDTFlags; /* DrawText flags */
COLORREF clrInsertMark; /* insert mark color */
COLORREF clrBtnHighlight; /* color for Flat Separator */
COLORREF clrBtnShadow; /* color for Flag Separator */
INT iVersion;
LPWSTR pszTooltipText; /* temporary store for a string > 80 characters
* for TTN_GETDISPINFOW notification */
TBINSERTMARK tbim; /* info on insertion mark */
TBUTTON_INFO *buttons; /* pointer to button array */
LPWSTR *strings; /* pointer to string array */
TBITMAP_INFO *bitmaps;
} TOOLBAR_INFO, *PTOOLBAR_INFO;
/* used by customization dialog */
typedef struct
{
PTOOLBAR_INFO tbInfo;
HWND tbHwnd;
} CUSTDLG_INFO, *PCUSTDLG_INFO;
typedef struct
{
TBBUTTON btn;
BOOL bVirtual;
BOOL bRemovable;
WCHAR text[64];
} CUSTOMBUTTON, *PCUSTOMBUTTON;
typedef enum
{
IMAGE_LIST_DEFAULT,
IMAGE_LIST_HOT,
IMAGE_LIST_DISABLED
} IMAGE_LIST_TYPE;
#define SEPARATOR_WIDTH 8
#define TOP_BORDER 2
#define BOTTOM_BORDER 2
#define DDARROW_WIDTH 11
#define ARROW_HEIGHT 3
#define INSERTMARK_WIDTH 2
#define DEFPAD_CX 7
#define DEFPAD_CY 6
#define DEFLISTGAP 4
/* vertical padding used in list mode when image is present */
#define LISTPAD_CY 9
/* how wide to treat the bitmap if it isn't present */
#define NONLIST_NOTEXT_OFFSET 2
#define TOOLBAR_NOWHERE (-1)
#define TOOLBAR_GetInfoPtr(hwnd) ((TOOLBAR_INFO *)GetWindowLongPtrW(hwnd,0))
#define TOOLBAR_HasText(x, y) (TOOLBAR_GetText(x, y) ? TRUE : FALSE)
#define TOOLBAR_HasDropDownArrows(exStyle) ((exStyle & TBSTYLE_EX_DRAWDDARROWS) ? TRUE : FALSE)
/* Used to find undocumented extended styles */
#define TBSTYLE_EX_ALL (TBSTYLE_EX_DRAWDDARROWS | \
TBSTYLE_EX_UNDOC1 | \
TBSTYLE_EX_MIXEDBUTTONS | \
TBSTYLE_EX_HIDECLIPPEDBUTTONS)
/* all of the CCS_ styles */
#define COMMON_STYLES (CCS_TOP|CCS_NOMOVEY|CCS_BOTTOM|CCS_NORESIZE| \
CCS_NOPARENTALIGN|CCS_ADJUSTABLE|CCS_NODIVIDER|CCS_VERT)
#define GETIBITMAP(infoPtr, i) (infoPtr->iVersion >= 5 ? LOWORD(i) : i)
#define GETHIMLID(infoPtr, i) (infoPtr->iVersion >= 5 ? HIWORD(i) : 0)
#define GETDEFIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlDef, infoPtr->cimlDef, id)
#define GETHOTIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlHot, infoPtr->cimlHot, id)
#define GETDISIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlDis, infoPtr->cimlDis, id)
static const WCHAR themeClass[] = { 'T','o','o','l','b','a','r',0 };
static BOOL TOOLBAR_GetButtonInfo(const TOOLBAR_INFO *infoPtr, NMTOOLBARW *nmtb);
static BOOL TOOLBAR_IsButtonRemovable(const TOOLBAR_INFO *infoPtr, int iItem, PCUSTOMBUTTON btnInfo);
static HIMAGELIST TOOLBAR_GetImageList(const PIMLENTRY *pies, INT cies, INT id);
static PIMLENTRY TOOLBAR_GetImageListEntry(const PIMLENTRY *pies, INT cies, INT id);
static VOID TOOLBAR_DeleteImageList(PIMLENTRY **pies, INT *cies);
static HIMAGELIST TOOLBAR_InsertImageList(PIMLENTRY **pies, INT *cies, HIMAGELIST himl, INT id);
static LRESULT TOOLBAR_LButtonDown(HWND hwnd, WPARAM wParam, LPARAM lParam);
static void TOOLBAR_SetHotItemEx (TOOLBAR_INFO *infoPtr, INT nHit, DWORD dwReason);
static void TOOLBAR_LayoutToolbar(HWND hwnd);
static LRESULT TOOLBAR_AutoSize(HWND hwnd);
static void TOOLBAR_CheckImageListIconSize(TOOLBAR_INFO *infoPtr);
static void TOOLBAR_TooltipSetRect(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *button);
static LRESULT
TOOLBAR_NotifyFormat(const TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam);
static inline int default_top_margin(const TOOLBAR_INFO *infoPtr)
{
return (infoPtr->dwStyle & TBSTYLE_FLAT ? 0 : TOP_BORDER);
}
static LPWSTR
TOOLBAR_GetText(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *btnPtr)
{
LPWSTR lpText = NULL;
/* NOTE: iString == -1 is undocumented */
if ((HIWORD(btnPtr->iString) != 0) && (btnPtr->iString != -1))
lpText = (LPWSTR)btnPtr->iString;
else if ((btnPtr->iString >= 0) && (btnPtr->iString < infoPtr->nNumStrings))
lpText = infoPtr->strings[btnPtr->iString];
return lpText;
}
static void
TOOLBAR_DumpButton(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *bP, INT btn_num, BOOL internal)
{
if (TRACE_ON(toolbar)){
TRACE("button %d id %d, bitmap=%d, state=%02x, style=%02x, data=%08lx, stringid=0x%08lx\n",
btn_num, bP->idCommand, GETIBITMAP(infoPtr, bP->iBitmap),
bP->fsState, bP->fsStyle, bP->dwData, bP->iString);
TRACE("string %s\n", debugstr_w(TOOLBAR_GetText(infoPtr,bP)));
if (internal)
TRACE("button %d id %d, hot=%s, row=%d, rect=(%d,%d)-(%d,%d)\n",
btn_num, bP->idCommand,
(bP->bHot) ? "TRUE":"FALSE", bP->nRow,
bP->rect.left, bP->rect.top,
bP->rect.right, bP->rect.bottom);
}
}
static void
TOOLBAR_DumpToolbar(const TOOLBAR_INFO *iP, INT line)
{
if (TRACE_ON(toolbar)) {
INT i;
TRACE("toolbar %p at line %d, exStyle=%08x, buttons=%d, bitmaps=%d, strings=%d, style=%08x\n",
iP->hwndSelf, line,
iP->dwExStyle, iP->nNumButtons, iP->nNumBitmaps,
iP->nNumStrings, iP->dwStyle);
TRACE("toolbar %p at line %d, himlInt=%p, himlDef=%p, himlHot=%p, himlDis=%p, redrawable=%s\n",
iP->hwndSelf, line,
iP->himlInt, iP->himlDef, iP->himlHot, iP->himlDis,
(iP->bDoRedraw) ? "TRUE" : "FALSE");
for(i=0; i<iP->nNumButtons; i++) {
TOOLBAR_DumpButton(iP, &iP->buttons[i], i, TRUE);
}
}
}
/***********************************************************************
* TOOLBAR_CheckStyle
*
* This function validates that the styles set are implemented and
* issues FIXME's warning of possible problems. In a perfect world this
* function should be null.
*/
static void
TOOLBAR_CheckStyle (HWND hwnd, DWORD dwStyle)
{
if (dwStyle & TBSTYLE_REGISTERDROP)
FIXME("[%p] TBSTYLE_REGISTERDROP not implemented\n", hwnd);
}
static INT
TOOLBAR_SendNotify (NMHDR *nmhdr, const TOOLBAR_INFO *infoPtr, UINT code)
{
if(!IsWindow(infoPtr->hwndSelf))
return 0; /* we have just been destroyed */
nmhdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
nmhdr->hwndFrom = infoPtr->hwndSelf;
nmhdr->code = code;
TRACE("to window %p, code=%08x, %s\n", infoPtr->hwndNotify, code,
(infoPtr->bUnicode) ? "via Unicode" : "via ANSI");
return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY,
(WPARAM)nmhdr->idFrom, (LPARAM)nmhdr);
}
/***********************************************************************
* TOOLBAR_GetBitmapIndex
*
* This function returns the bitmap index associated with a button.
* If the button specifies I_IMAGECALLBACK, then the TBN_GETDISPINFO
* is issued to retrieve the index.
*/
static INT
TOOLBAR_GetBitmapIndex(const TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr)
{
INT ret = btnPtr->iBitmap;
if (ret == I_IMAGECALLBACK)
{
/* issue TBN_GETDISPINFO */
NMTBDISPINFOW nmgd;
memset(&nmgd, 0, sizeof(nmgd));
nmgd.idCommand = btnPtr->idCommand;
nmgd.lParam = btnPtr->dwData;
nmgd.dwMask = TBNF_IMAGE;
nmgd.iImage = -1;
/* Windows also send TBN_GETDISPINFOW even if the control is ANSI */
TOOLBAR_SendNotify(&nmgd.hdr, infoPtr, TBN_GETDISPINFOW);
if (nmgd.dwMask & TBNF_DI_SETITEM)
btnPtr->iBitmap = nmgd.iImage;
ret = nmgd.iImage;
TRACE("TBN_GETDISPINFO returned bitmap id %d, mask=%08x, nNumBitmaps=%d\n",
ret, nmgd.dwMask, infoPtr->nNumBitmaps);
}
if (ret != I_IMAGENONE)
ret = GETIBITMAP(infoPtr, ret);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -