
--proc/controls/comboboxex: comctl32 combobox control
--Written by Cosmin Apreutesei. Public Domain.

setfenv(1, require'winapi')
require'winapi.combobox'
require'winapi.comctl'
require'winapi.itemlist'

InitCommonControlsEx(ICC_USEREX_CLASSES)

--creation

WC_COMBOBOXEX = 'ComboBoxEx32'

CBES_EX_NOEDITIMAGE           = 0x00000001
CBES_EX_NOEDITIMAGEINDENT     = 0x00000002
CBES_EX_PATHWORDBREAKPROC     = 0x00000004
CBES_EX_NOSIZELIMIT           = 0x00000008
CBES_EX_CASESENSITIVE         = 0x00000010
CBES_EX_TEXTENDELLIPSIS       = 0x00000020 --vista+

--commands

CBEM_SETIMAGELIST        = (WM_USER + 2)
CBEM_GETIMAGELIST        = (WM_USER + 3)
CBEM_DELETEITEM          = CB_DELETESTRING
CBEM_GETCOMBOCONTROL     = (WM_USER + 6)
CBEM_GETEDITCONTROL      = (WM_USER + 7)
CBEM_SETEXTENDEDSTYLE    = (WM_USER + 14) -- lparam == new style, wParam (optional) == mask
CBEM_GETEXTENDEDSTYLE    = (WM_USER + 9)
CBEM_SETUNICODEFORMAT    = CCM_SETUNICODEFORMAT
CBEM_GETUNICODEFORMAT    = CCM_GETUNICODEFORMAT
CBEM_HASEDITCHANGED      = (WM_USER + 10)
CBEM_INSERTITEMW         = (WM_USER + 11)
CBEM_SETITEMW            = (WM_USER + 12)
CBEM_GETITEMW            = (WM_USER + 13)

function ComboBoxEx_SetImageList(hwnd, iml)
	return ffi.cast('HIMAGELIST', SNDMSG(hwnd, CBEM_SETIMAGELIST, 0, iml))
end

function ComboBoxEx_GetImageList(hwnd)
	return ffi.cast('HIMAGELIST', SNDMSG(hwnd, CBEM_GETIMAGELIST))
end

ffi.cdef[[
typedef struct tagCOMBOBOXEXITEMW
{
	 UINT mask;
	 INT_PTR iItem;
	 LPWSTR pszText;
	 int cchTextMax;
	 int iImage;
	 int iSelectedImage;
	 int iOverlay;
	 int iIndent;
	 LPARAM lParam;
} COMBOBOXEXITEMW, *PCOMBOBOXEXITEMW;
typedef COMBOBOXEXITEMW const *PCCOMBOEXITEMW;
]]

CBEIF_TEXT              = 0x00000001
CBEIF_IMAGE             = 0x00000002
CBEIF_SELECTEDIMAGE     = 0x00000004
CBEIF_OVERLAY           = 0x00000008
CBEIF_INDENT            = 0x00000010
CBEIF_LPARAM            = 0x00000020
CBEIF_DI_SETITEM        = 0x10000000

COMBOBOXEXITEM = struct{
	ctype = 'COMBOBOXEXITEMW', mask = 'mask',
	fields = mfields{
		'i', 'iItem', 0, countfrom0, countfrom1,
		'text', 'pszText', CBEIF_TEXT, wcs, mbs,
		'image', 'iImage', CBEIF_IMAGE, countfrom0, countfrom1,
		'selected_image', 'iSelectedImage', CBEIF_SELECTEDIMAGE, countfrom0, countfrom1,
		'overlay_image', 'iOverlay', CBEIF_OVERLAY, countfrom0, countfrom1,
		'indent', 'iIndent', CBEIF_INDENT, pass, pass,
	}
}

function ComboBoxEx_InsertItem(hwnd, item) --returns index
	item = COMBOBOXEXITEM(item)
	return countfrom1(checkpoz(SNDMSG(hwnd, CBEM_INSERTITEMW, 0,
										ffi.cast('PCOMBOBOXEXITEMW', item)))), item
end

ComboBox_DeleteItem = ComboBox_DeleteString

function ComboBoxEx_GetItem(hwnd, item)
	item = COMBOBOXEXITEM:setmask(item)
	local ws, sz
	if not ptr(item.pszText) then --user didn't supply a buffer
		ws, sz = WCS()
		item.text = ws --we set text so that ws gets pinned to item
		item.cchTextMax = sz
	else
		ws = item.pszText
		sz = item.cchTextMax
	end
	checknz(SNDMSG(hwnd, CBEM_GETITEMW, 0, ffi.cast('PCOMBOBOXEXITEMW', item)))
	--winapi can relocate pszText; if so we need to copy the string and relocate pszText back.
	--note: we go through this trouble because otherwise we would make the valididy of the
	--struct's contents dependent on the lifetime of the combobox item.
	if item.pszText ~= ws then
		wcsncpy(ws, item.pszText, sz)
		item.pszText = ws
	end
	return item
end

function ComboBoxEx_SetItem(hwnd, item)
	item = COMBOBOXEXITEM(item)
	checknz(SNDMSG(hwnd, CBEM_SETITEMW, 0, ffi.cast('PCOMBOBOXEXITEMW', item)))
	return item
end


--notifications

--[[

typedef struct {
    NMHDR hdr;
    COMBOBOXEXITEMA ceItem;
} NMCOMBOBOXEXA, *PNMCOMBOBOXEXA;

typedef struct {
    NMHDR hdr;
    COMBOBOXEXITEMW ceItem;
} NMCOMBOBOXEXW, *PNMCOMBOBOXEXW;

#ifdef UNICODE
#define NMCOMBOBOXEX            NMCOMBOBOXEXW
#define PNMCOMBOBOXEX           PNMCOMBOBOXEXW
#define CBEN_GETDISPINFO        CBEN_GETDISPINFOW
#else
#define NMCOMBOBOXEX            NMCOMBOBOXEXA
#define PNMCOMBOBOXEX           PNMCOMBOBOXEXA
#define CBEN_GETDISPINFO        CBEN_GETDISPINFOA
#endif

#else
typedef struct {
    NMHDR hdr;
    COMBOBOXEXITEM ceItem;
} NMCOMBOBOXEX, *PNMCOMBOBOXEX;

#define CBEN_GETDISPINFO         (CBEN_FIRST - 0)

#endif      // _WIN32_IE >= 0x0400

#if (_WIN32_IE >= 0x0400)
#define CBEN_GETDISPINFOA        (CBEN_FIRST - 0)
#endif
#define CBEN_INSERTITEM          (CBEN_FIRST - 1)
#define CBEN_DELETEITEM          (CBEN_FIRST - 2)
#define CBEN_BEGINEDIT           (CBEN_FIRST - 4)
#define CBEN_ENDEDITA            (CBEN_FIRST - 5)
#define CBEN_ENDEDITW            (CBEN_FIRST - 6)

#if (_WIN32_IE >= 0x0400)
#define CBEN_GETDISPINFOW        (CBEN_FIRST - 7)
#endif

#if (_WIN32_IE >= 0x0400)
#define CBEN_DRAGBEGINA                  (CBEN_FIRST - 8)
#define CBEN_DRAGBEGINW                  (CBEN_FIRST - 9)

#ifdef UNICODE
#define CBEN_DRAGBEGIN CBEN_DRAGBEGINW
#else
#define CBEN_DRAGBEGIN CBEN_DRAGBEGINA
#endif

#endif  //(_WIN32_IE >= 0x0400)

// lParam specifies why the endedit is happening
#ifdef UNICODE
#define CBEN_ENDEDIT CBEN_ENDEDITW
#else
#define CBEN_ENDEDIT CBEN_ENDEDITA
#endif

#define CBENF_KILLFOCUS         1
#define CBENF_RETURN            2
#define CBENF_ESCAPE            3
#define CBENF_DROPDOWN          4

#define CBEMAXSTRLEN 260

#if (_WIN32_IE >= 0x0400)
// CBEN_DRAGBEGIN sends this information ...

typedef struct {
    NMHDR hdr;
    int   iItemid;
    WCHAR szText[CBEMAXSTRLEN];
}NMCBEDRAGBEGINW, *LPNMCBEDRAGBEGINW, *PNMCBEDRAGBEGINW;


typedef struct {
    NMHDR hdr;
    int   iItemid;
    char szText[CBEMAXSTRLEN];
}NMCBEDRAGBEGINA, *LPNMCBEDRAGBEGINA, *PNMCBEDRAGBEGINA;

#ifdef UNICODE
#define  NMCBEDRAGBEGIN NMCBEDRAGBEGINW
#define  LPNMCBEDRAGBEGIN LPNMCBEDRAGBEGINW
#define  PNMCBEDRAGBEGIN PNMCBEDRAGBEGINW
#else
#define  NMCBEDRAGBEGIN NMCBEDRAGBEGINA
#define  LPNMCBEDRAGBEGIN LPNMCBEDRAGBEGINA
#define  PNMCBEDRAGBEGIN PNMCBEDRAGBEGINA
#endif
#endif      // _WIN32_IE >= 0x0400

// CBEN_ENDEDIT sends this information...
// fChanged if the user actually did anything
// iNewSelection gives what would be the new selection unless the notify is failed
//                      iNewSelection may be CB_ERR if there's no match
typedef struct {
        NMHDR hdr;
        BOOL fChanged;
        int iNewSelection;
        WCHAR szText[CBEMAXSTRLEN];
        int iWhy;
} NMCBEENDEDITW, *LPNMCBEENDEDITW, *PNMCBEENDEDITW;

typedef struct {
        NMHDR hdr;
        BOOL fChanged;
        int iNewSelection;
        char szText[CBEMAXSTRLEN];
        int iWhy;
} NMCBEENDEDITA, *LPNMCBEENDEDITA,*PNMCBEENDEDITA;

#ifdef UNICODE
#define  NMCBEENDEDIT NMCBEENDEDITW
#define  LPNMCBEENDEDIT LPNMCBEENDEDITW
#define  PNMCBEENDEDIT PNMCBEENDEDITW
#else
#define  NMCBEENDEDIT NMCBEENDEDITA
#define  LPNMCBEENDEDIT LPNMCBEENDEDITA
#define  PNMCBEENDEDIT PNMCBEENDEDITA
#endif

#endif

#endif      // _WIN32_IE >= 0x0300
]]

