
--proc/controls/toolbar: standard toolbar control
--Written by Cosmin Apreutesei. Public Domain.

setfenv(1, require'winapi')
require'winapi.window'
require'winapi.comctl'

--creation

TOOLBARCLASSNAME       = 'ToolbarWindow32'

TBSTYLE_TOOLTIPS         = 0x0100
TBSTYLE_WRAPABLE         = 0x0200
TBSTYLE_ALTDRAG          = 0x0400
TBSTYLE_FLAT             = 0x0800
TBSTYLE_LIST             = 0x1000
TBSTYLE_CUSTOMERASE      = 0x2000
TBSTYLE_REGISTERDROP     = 0x4000
TBSTYLE_TRANSPARENT      = 0x8000

BTNS_BUTTON      = 0x0000
BTNS_SEP         = 0x0001
BTNS_CHECK       = 0x0002
BTNS_GROUP       = 0x0004
BTNS_DROPDOWN    = 0x0008
BTNS_AUTOSIZE    = 0x0010 --automatically calculate the cx of the button
BTNS_NOPREFIX    = 0x0020 --this button should not have accel prefix
BTNS_SHOWTEXT    = 0x0040 -- ignored unless TBSTYLE_EX_MIXEDBUTTONS is set
BTNS_WHOLEDROPDOWN = 0x0080 -- draw drop-down arrow, but without split arrow section

TBSTYLE_EX_MIXEDBUTTONS              = 0x00000008
TBSTYLE_EX_HIDECLIPPEDBUTTONS        = 0x00000010 -- don't show partially obscured buttons
TBSTYLE_EX_DOUBLEBUFFER              = 0x00000080 -- Double Buffer the toolbar
TBSTYLE_EX_DRAWDDARROWS              = 0x00000001

--commands

TB_SETIMAGELIST          = (WM_USER + 48)
TB_GETIMAGELIST          = (WM_USER + 49)
TB_LOADIMAGES            = (WM_USER + 50)
TB_BUTTONSTRUCTSIZE      = (WM_USER + 30)
TB_ADDBUTTONS            = (WM_USER + 68)
TB_AUTOSIZE              = (WM_USER + 33)
TB_INSERTBUTTONW         = (WM_USER + 67)
TB_DELETEBUTTON          = (WM_USER + 22)
TB_BUTTONCOUNT           = (WM_USER + 24)

function Toolbar_SetImageList(tb, iml)
	return ptr(ffi.cast('HIMAGELIST', SNDMSG(tb, TB_SETIMAGELIST, 0, iml)))
end

function Toolbar_GetImageList(tb)
	return ptr(ffi.cast('HIMAGELIST', SNDMSG(tb, TB_GETIMAGELIST)))
end

IDB_STD_SMALL_COLOR      = 0
IDB_STD_LARGE_COLOR      = 1
IDB_VIEW_SMALL_COLOR     = 4
IDB_VIEW_LARGE_COLOR     = 5
IDB_HIST_SMALL_COLOR     = 8
IDB_HIST_LARGE_COLOR     = 9
IDB_HIST_NORMAL          = 12
IDB_HIST_HOT             = 13
IDB_HIST_DISABLED        = 14
IDB_HIST_PRESSED         = 15

HINST_COMMCTRL           = -1

function Toolbar_LoadImages(tb, IDB)
	return checkpoz(SNDMSG(tb, TB_LOADIMAGES, IDB, ffi.cast('HINSTANCE', HINST_COMMCTRL)))
end

--index values for IDB_HIST_LARGE_COLOR and IDB_HIST_SMALL_COLOR
HIST_BACK                = 0
HIST_FORWARD             = 1
HIST_FAVORITES           = 2
HIST_ADDTOFAVORITES      = 3
HIST_VIEWTREE            = 4
--index values for IDB_STD_LARGE_COLOR and IDB_STD_SMALL_COLOR
STD_CUT                  = 0
STD_COPY                 = 1
STD_PASTE                = 2
STD_UNDO                 = 3
STD_REDOW                = 4
STD_DELETE               = 5
STD_FILENEW              = 6
STD_FILEOPEN             = 7
STD_FILESAVE             = 8
STD_PRINTPRE             = 9
STD_PROPERTIES           = 10
STD_HELP                 = 11
STD_FIND                 = 12
STD_REPLACE              = 13
STD_PRINT                = 14
--Index values for IDB_VIEW_LARGE_COLOR and IDB_VIEW_SMALL_COLOR
VIEW_LARGEICONS          = 0
VIEW_SMALLICONS          = 1
VIEW_LIST                = 2
VIEW_DETAILS             = 3
VIEW_SORTNAME            = 4
VIEW_SORTSIZE            = 5
VIEW_SORTDATE            = 6
VIEW_SORTTYPE            = 7
VIEW_PARENTFOLDER        = 8
VIEW_NETCONNECT          = 9
VIEW_NETDISCONNECT       = 10
VIEW_NEWFOLDER           = 11
VIEW_VIEWMENU            = 12

TBSTATE_CHECKED          = 0x01
TBSTATE_PRESSED          = 0x02
TBSTATE_ENABLED          = 0x04
TBSTATE_HIDDEN           = 0x08
TBSTATE_INDETERMINATE    = 0x10
TBSTATE_WRAP             = 0x20
TBSTATE_ELLIPSES         = 0x40
TBSTATE_MARKED           = 0x80

ffi.cdef(string.format([[
typedef struct _TBBUTTON {
    int iBitmap;
    int idCommand;
    BYTE fsState;
    BYTE fsStyle;
    BYTE bReserved[%d];
    DWORD_PTR dwData;
    union {
		WCHAR* pString;
		INT_PTR iString;
	};
} TBBUTTON, *PTBBUTTON, *LPTBBUTTON;
typedef const TBBUTTON *LPCTBBUTTON;
]], ffi.abi('64bit') and 6 or 2))

local style_bitmask = bitmask{
	auto_width = BTNS_AUTOSIZE,
	toggle = BTNS_CHECK,
	group = BTNS_GROUP, --use with `pushed`
	type = {
		button = 0,
		dropdown = BTNS_WHOLEDROPDOWN,
		button_with_dropdown = BTNS_DROPDOWN,
		separator = BTNS_SEP,
	},
	accelerator_prefix = negate(BTNS_NOPREFIX),
	show_text = BTNS_SHOWTEXT, --use with `list` and `mixed_buttons`
}

local function set_style(t, cdata)
	return style_bitmask:set(cdata.fsStyle, t)
end

local function get_style(fsStyle)
	return style_bitmask:get(fsStyle)
end

TBBUTTON = struct{
	ctype = 'TBBUTTON',
	fields = sfields{
		'i', 'iBitmap', countfrom0, countfrom1,
		'command', 'idCommand', pass, pass,
		'__state', 'fsState', flags, pass, --TBSTATE_*
		'style', 'fsStyle', set_style, get_style, --TBSTYLE_*
		'text', 'pString', wcs, pass, --used as pointer
		'text_index', 'iString', pass, pass, --used as index
	},
	bitfields = {
		state = {'__state', '__state', 'TBSTATE'},
	},
	defaults = {
		state = {enabled = true},
	},
}

function Toolbar_AddButton(tb, button) --TODO: support an array of buttons
	button = TBBUTTON(button)
	SNDMSG(tb, TB_BUTTONSTRUCTSIZE, ffi.sizeof(button))
	checknz(SNDMSG(tb, TB_ADDBUTTONS, 1, ffi.cast('TBBUTTON*', button)))
	SNDMSG(tb, TB_AUTOSIZE)
end

function Toolbar_InsertButton(tb, i, button)
	button = TBBUTTON(button)
	SNDMSG(tb, TB_BUTTONSTRUCTSIZE, ffi.sizeof(button))
	checktrue(SNDMSG(tb, TB_INSERTBUTTON, countfrom0(i), ffi.cast('BBUTTON*', button)))
end

function Toolbar_DeleteButton(tb, i)
	return checktrue(SNDMSG(tb, countfrom0(i)))
end

function Toolbar_GetButtonCount(tb)
	return checkpoz(SNDMSG(tb, TB_BUTTONCOUNT))
end

TBIF_IMAGE    = 0x00000001
TBIF_TEXT     = 0x00000002
TBIF_STATE    = 0x00000004
TBIF_STYLE    = 0x00000008
TBIF_LPARAM   = 0x00000010
TBIF_COMMAND  = 0x00000020
TBIF_SIZE     = 0x00000040
TBIF_BYINDEX  = 0x80000000 -- wParam in Get/SetButtonInfo is an index, not id

ffi.cdef[[
typedef struct {
    UINT cbSize;
    DWORD dwMask;
    int idCommand;
    int iImage;
    BYTE fsState;
    BYTE fsStyle;
    WORD cx;
    DWORD_PTR lParam;
    LPWSTR pszText;
    int cchText;
} TBBUTTONINFOW, *LPTBBUTTONINFOW;
]]

TBBUTTONINFO = struct{
	ctype = 'TBBUTTONINFOW', size = 'cbSize', mask = 'dwMask',
	fields = mfields{
		'id', 'idCommand', TBIF_COMMAND, pass, pass,
		'i', 'iImage', TBIF_IMAGE, countfrom0, countfrom1,
		'text', 'pszText', TBIF_TEXT, wcs, mbs,
		'state', 'fsState', TBIF_STATE, flags, pass,
		'style','fsStyle', TBIF_STYLE, flags, pass,
		'w', 'cx', TBIF_SIZE, pass, pass,
		'user_data', 'lParam', TBIF_LPARAM, pass, pass,
		'by_index', '', TBIF_BYINDEX, pass, pass,
	},
}

-- BUTTONINFO APIs do NOT support the string pool.
TB_GETBUTTONINFO = (WM_USER + 63)
TB_SETBUTTONINFO = (WM_USER + 64)

function Toolbar_GetButtonInfo(tb, i, info)
	info = TBBUTTONINFO:setmask(info)
	if bit.band(info.fsState, TBIF_BYINDEX) ~= 0 then
		i = countfrom0(i)
	end
	checkpoz(SNDMSG(tb, TB_GETBUTTONINFO, i, ffi.cast('TBBUTTONINFOW*', info)))
	return info
end

function Toolbar_SetButtonInfo(tb, i, info)
	info = TBBUTTONINFO(info)
	if bit.band(info.fsState, TBIF_BYINDEX) ~= 0 then i = countfrom0(i) end
	checkpoz(SNDMSG(tb, TB_SETBUTTONINFO, i, ffi.cast('TBBUTTONINFOW*', info)))
end


CMB_MASKED               = 0x02

TB_ENABLEBUTTON          = (WM_USER + 1)
TB_CHECKBUTTON           = (WM_USER + 2)
TB_PRESSBUTTON           = (WM_USER + 3)
TB_HIDEBUTTON            = (WM_USER + 4)
TB_INDETERMINATE         = (WM_USER + 5)
TB_MARKBUTTON            = (WM_USER + 6)
TB_ISBUTTONENABLED       = (WM_USER + 9)
TB_ISBUTTONCHECKED       = (WM_USER + 10)
TB_ISBUTTONPRESSED       = (WM_USER + 11)
TB_ISBUTTONHIDDEN        = (WM_USER + 12)
TB_ISBUTTONINDETERMINATE = (WM_USER + 13)
TB_ISBUTTONHIGHLIGHTED   = (WM_USER + 14)
TB_SETSTATE              = (WM_USER + 17)
TB_GETSTATE              = (WM_USER + 18)
TB_ADDBITMAP             = (WM_USER + 19)
TB_GETBUTTON             = (WM_USER + 23)
TB_COMMANDTOINDEX        = (WM_USER + 25)
TB_SAVERESTOREW          = (WM_USER + 76)
TB_CUSTOMIZE             = (WM_USER + 27)
TB_ADDSTRINGW            = (WM_USER + 77)
TB_GETITEMRECT           = (WM_USER + 29)
TB_SETBUTTONSIZE         = (WM_USER + 31)
TB_SETBITMAPSIZE         = (WM_USER + 32)
TB_GETTOOLTIPS           = (WM_USER + 35)
TB_SETTOOLTIPS           = (WM_USER + 36)
TB_SETPARENT             = (WM_USER + 37)
TB_SETROWS               = (WM_USER + 39)
TB_GETROWS               = (WM_USER + 40)
TB_SETCMDID              = (WM_USER + 42)
TB_CHANGEBITMAP          = (WM_USER + 43)
TB_GETBITMAP             = (WM_USER + 44)
TB_REPLACEBITMAP         = (WM_USER + 46)
TB_SETINDENT             = (WM_USER + 47)
TB_GETRECT               = (WM_USER + 51) -- wParam is the Cmd instead of index
TB_SETHOTIMAGELIST       = (WM_USER + 52)
TB_GETHOTIMAGELIST       = (WM_USER + 53)
TB_SETDISABLEDIMAGELIST  = (WM_USER + 54)
TB_GETDISABLEDIMAGELIST  = (WM_USER + 55)
TB_SETSTYLE              = (WM_USER + 56)
TB_GETSTYLE              = (WM_USER + 57)
TB_GETBUTTONSIZE         = (WM_USER + 58)
TB_SETBUTTONWIDTH        = (WM_USER + 59)
TB_SETMAXTEXTROWS        = (WM_USER + 60)
TB_GETTEXTROWS           = (WM_USER + 61)
TB_GETOBJECT             = (WM_USER + 62)  -- wParam == IID, lParam void **ppv
TB_GETHOTITEM            = (WM_USER + 71)
TB_SETHOTITEM            = (WM_USER + 72)  -- wParam == iHotItem
TB_SETANCHORHIGHLIGHT    = (WM_USER + 73)  -- wParam == TRUE/FALSE
TB_GETANCHORHIGHLIGHT    = (WM_USER + 74)
TB_GETBUTTONTEXTW        = (WM_USER + 75)
TB_GETINSERTMARK         = (WM_USER + 79)  -- lParam == LPTBINSERTMARK
TB_SETINSERTMARK         = (WM_USER + 80)  -- lParam == LPTBINSERTMARK
TB_INSERTMARKHITTEST     = (WM_USER + 81)  -- wParam == LPPOINT lParam == LPTBINSERTMARK
TB_MOVEBUTTON            = (WM_USER + 82)
TB_GETMAXSIZE            = (WM_USER + 83)  -- lParam == LPSIZE
TB_SETEXTENDEDSTYLE      = (WM_USER + 84)  -- For TBSTYLE_EX_*
TB_GETEXTENDEDSTYLE      = (WM_USER + 85)  -- For TBSTYLE_EX_*
TB_GETPADDING            = (WM_USER + 86)
TB_SETPADDING            = (WM_USER + 87)
TB_SETINSERTMARKCOLOR    = (WM_USER + 88)
TB_GETINSERTMARKCOLOR    = (WM_USER + 89)
TB_SETCOLORSCHEME        = CCM_SETCOLORSCHEME  -- lParam is color scheme
TB_GETCOLORSCHEME        = CCM_GETCOLORSCHEME      -- fills in COLORSCHEME pointed to by lParam
TB_SETUNICODEFORMAT      = CCM_SETUNICODEFORMAT
TB_GETUNICODEFORMAT      = CCM_GETUNICODEFORMAT
TB_MAPACCELERATORW       = (WM_USER + 90)  -- wParam == ch, lParam int * pidBtn


function Toolbar_GetButtonText(tb, i, buf)
	if not buf then
		local sz = checkpoz(SNDMSG(tb, TB_GETBUTTONTEXTW, countfrom0(i)))
		buf = WCS(sz)
	end
	checkpoz(SNDMSG(tb, TB_GETBUTTONTEXTW, i, buf))
	return buf or mbs(buf)
end

-- Custom Draw Structure
ffi.cdef[[
typedef struct _NMTBCUSTOMDRAW {
    NMCUSTOMDRAW nmcd;
    HBRUSH hbrMonoDither;
    HBRUSH hbrLines;                // For drawing lines on buttons
    HPEN hpenLines;                 // For drawing lines on buttons
    COLORREF clrText;               // Color of text
    COLORREF clrMark;               // Color of text bk when marked. (only if TBSTATE_MARKED)
    COLORREF clrTextHighlight;      // Color of text when highlighted
    COLORREF clrBtnFace;            // Background of the button
    COLORREF clrBtnHighlight;       // 3D highlight
    COLORREF clrHighlightHotTrack;  // In conjunction with fHighlightHotTrack will cause button to highlight like a menu
    RECT rcText;                    // Rect for text
    int nStringBkMode;
    int nHLStringBkMode;
    int iListGap;
} NMTBCUSTOMDRAW, * LPNMTBCUSTOMDRAW;
]]

-- Toolbar custom draw return flags
TBCDRF_NOEDGES               = 0x00010000  -- Don't draw button edges
TBCDRF_HILITEHOTTRACK        = 0x00020000  -- Use color of the button bk when hottracked
TBCDRF_NOOFFSET              = 0x00040000  -- Don't offset button if pressed
TBCDRF_NOMARK                = 0x00080000  -- Don't draw default highlight of image/text for TBSTATE_MARKED
TBCDRF_NOETCHEDEFFECT        = 0x00100000  -- Don't draw etched effect for disabled items
TBCDRF_BLENDICON             = 0x00200000  -- Use ILD_BLEND50 on the icon image
TBCDRF_NOBACKGROUND          = 0x00400000  -- Use ILD_BLEND50 on the icon image
TBCDRF_USECDCOLORS           = 0x00800000  -- Use CustomDrawColors to RenderText regardless of VisualStyle

ffi.cdef[[
typedef struct tagTBADDBITMAP {
        HINSTANCE       hInst;
        UINT_PTR        nID;
} TBADDBITMAP, *LPTBADDBITMAP;

typedef struct tagTBSAVEPARAMSW {
    HKEY hkr;
    LPCWSTR pszSubKey;
    LPCWSTR pszValueName;
} TBSAVEPARAMSW, *LPTBSAVEPARAMW;

typedef struct {
    int   iButton;
    DWORD dwFlags;
} TBINSERTMARK, * LPTBINSERTMARK;
]]

TBIMHT_AFTER       = 0x00000001 -- TRUE = insert After iButton, otherwise before
TBIMHT_BACKGROUND  = 0x00000002 -- TRUE iff missed buttons completely

ffi.cdef[[
typedef struct {
    HINSTANCE       hInstOld;
    UINT_PTR        nIDOld;
    HINSTANCE       hInstNew;
    UINT_PTR        nIDNew;
    int             nButtons;
} TBREPLACEBITMAP, *LPTBREPLACEBITMAP;
]]

TBBF_LARGE               = 0x0001

TB_GETBITMAPFLAGS        = (WM_USER + 41)
TB_HITTEST               = (WM_USER + 69)

-- New post Win95/NT4 for InsertButton and AddButton.  if iString member
-- is a pointer to a string, it will be handled as a string like listview
-- (although LPSTR_TEXTCALLBACK is not supported).

TB_SETDRAWTEXTFLAGS      = (WM_USER + 70)  -- wParam == mask lParam == bit values
TB_GETSTRINGW            = (WM_USER + 91)
TB_SETHOTITEM2           = (WM_USER + 94)  -- wParam == iHotItem,  lParam = dwFlags
TB_SETLISTGAP            = (WM_USER + 96)
TB_GETIMAGELISTCOUNT     = (WM_USER + 98)
TB_GETIDEALSIZE          = (WM_USER + 99)  -- wParam == fHeight, lParam = psize
-- before using WM_USER + 103, recycle old space above (WM_USER + 97)
--TODO: TB_TRANSLATEACCELERATOR      = CCM_TRANSLATEACCELERATOR

TBMF_PAD                 = 0x00000001
TBMF_BARPAD              = 0x00000002
TBMF_BUTTONSPACING       = 0x00000004

ffi.cdef[[
typedef struct {
    UINT cbSize;
    DWORD dwMask;

    int cxPad;        // PAD
    int cyPad;
    int cxBarPad;     // BARPAD
    int cyBarPad;
    int cxButtonSpacing;   // BUTTONSPACING
    int cyButtonSpacing;
} TBMETRICS, * LPTBMETRICS;
]]

TB_GETMETRICS            = (WM_USER + 101)
TB_SETMETRICS            = (WM_USER + 102)
TB_GETITEMDROPDOWNRECT   = (WM_USER + 103)  -- Rect of item's drop down button
TB_SETPRESSEDIMAGELIST   = (WM_USER + 104)
TB_GETPRESSEDIMAGELIST   = (WM_USER + 105)
TB_SETWINDOWTHEME        = CCM_SETWINDOWTHEME

TBN_FIRST                = tonumber(ffi.cast('UINT', -700))

update(WM_NOTIFY_NAMES, constants{
	TBN_GETBUTTONINFOA       = TBN_FIRST-0,
	TBN_BEGINDRAG            = TBN_FIRST-1,
	TBN_ENDDRAG              = TBN_FIRST-2,
	TBN_BEGINADJUST          = TBN_FIRST-3,
	TBN_ENDADJUST            = TBN_FIRST-4,
	TBN_RESET                = TBN_FIRST-5,
	TBN_QUERYINSERT          = TBN_FIRST-6,
	TBN_QUERYDELETE          = TBN_FIRST-7,
	TBN_TOOLBARCHANGE        = TBN_FIRST-8,
	TBN_CUSTHELP             = TBN_FIRST-9,
	TBN_DROPDOWN             = TBN_FIRST-10,
	TBN_GETOBJECT            = TBN_FIRST-12,
})

-- Structure for TBN_HOTITEMCHANGE notification
ffi.cdef[[
typedef struct tagNMTBHOTITEM
{
    NMHDR   hdr;
    int     idOld;
    int     idNew;
    DWORD   dwFlags;           // HICF_*
} NMTBHOTITEM, * LPNMTBHOTITEM;
]]

-- Hot item change flags
HICF_OTHER           = 0x00000000
HICF_MOUSE           = 0x00000001          -- Triggered by mouse
HICF_ARROWKEYS       = 0x00000002          -- Triggered by arrow keys
HICF_ACCELERATOR     = 0x00000004          -- Triggered by accelerator
HICF_DUPACCEL        = 0x00000008          -- This accelerator is not unique
HICF_ENTERING        = 0x00000010          -- idOld is invalid
HICF_LEAVING         = 0x00000020          -- idNew is invalid
HICF_RESELECT        = 0x00000040          -- hot item reselected
HICF_LMOUSE          = 0x00000080          -- left mouse button selected
HICF_TOGGLEDROPDOWN  = 0x00000100          -- Toggle button's dropdown state

TBN_HOTITEMCHANGE        = (TBN_FIRST - 13)
TBN_DRAGOUT              = (TBN_FIRST - 14) -- this is sent when the user clicks down on a button then drags off the button
TBN_DELETINGBUTTON       = (TBN_FIRST - 15) -- uses TBNOTIFY
TBN_GETDISPINFOA         = (TBN_FIRST - 16) -- This is sent when the  toolbar needs  some display information
TBN_GETDISPINFOW         = (TBN_FIRST - 17) -- This is sent when the  toolbar needs  some display information
TBN_GETINFOTIPA          = (TBN_FIRST - 18)
TBN_GETINFOTIPW          = (TBN_FIRST - 19)
TBN_GETBUTTONINFOW       = (TBN_FIRST - 20)
TBN_RESTORE              = (TBN_FIRST - 21)
TBN_SAVE                 = (TBN_FIRST - 22)
TBN_INITCUSTOMIZE        = (TBN_FIRST - 23)
TBNRF_HIDEHELP           = 0x00000001
TBNRF_ENDCUSTOMIZE       = 0x00000002
TBN_WRAPHOTITEM          = (TBN_FIRST - 24)
TBN_DUPACCELERATOR       = (TBN_FIRST - 25)
TBN_WRAPACCELERATOR      = (TBN_FIRST - 26)
TBN_DRAGOVER             = (TBN_FIRST - 27)
TBN_MAPACCELERATOR       = (TBN_FIRST - 28)

ffi.cdef[[
typedef struct tagNMTBSAVE
{
    NMHDR hdr;
    DWORD* pData;
    DWORD* pCurrent;
    UINT cbData;
    int iItem;
    int cButtons;
    TBBUTTON tbButton;
} NMTBSAVE, *LPNMTBSAVE;

typedef struct tagNMTBRESTORE
{
    NMHDR hdr;
    DWORD* pData;
    DWORD* pCurrent;
    UINT cbData;
    int iItem;
    int cButtons;
    int cbBytesPerRecord;
    TBBUTTON tbButton;
} NMTBRESTORE, *LPNMTBRESTORE;

typedef struct tagNMTBGETINFOTIPW
{
    NMHDR hdr;
    LPWSTR pszText;
    int cchTextMax;
    int iItem;
    LPARAM lParam;
} NMTBGETINFOTIPW, *LPNMTBGETINFOTIPW;
]]

TBNF_IMAGE               = 0x00000001
TBNF_TEXT                = 0x00000002
TBNF_DI_SETITEM          = 0x10000000

ffi.cdef[[
typedef struct {
    NMHDR hdr;
    DWORD dwMask;      // [in] Specifies the values requested .[out] Client ask the data to be set for future use
    int idCommand;     // [in] id of button we're requesting info for
    DWORD_PTR lParam;  // [in] lParam of button
    int iImage;        // [out] image index
    LPWSTR pszText;    // [out] new text for item
    int cchText;       // [in] size of buffer pointed to by pszText
} NMTBDISPINFOW, *LPNMTBDISPINFOW;
]]

-- Return codes for TBN_DROPDOWN
TBDDRET_DEFAULT          = 0
TBDDRET_NODEFAULT        = 1
TBDDRET_TREATPRESSED     = 2       -- Treat as a standard press button

ffi.cdef[[
typedef struct tagNMTOOLBARW {
    NMHDR     hdr;
    int       i;
    TBBUTTON  button;
    int       cchText;
    LPWSTR    pszText;
    RECT      rect;
} NMTOOLBARW, *LPNMTOOLBARW;

typedef NMTOOLBARW   TBNOTIFY;
typedef LPNMTOOLBARW LPTBNOTIFY;
]]

function NM.TBN_DROPDOWN(hdr)
	return ffi.cast('NMTOOLBARW*', hdr)
end
