
--oo/controls/combobox: ComboBoxEx32 control
--Written by Cosmin Apreutesei. Public Domain.

setfenv(1, require'winapi')
require'winapi.controlclass'
require'winapi.comboboxex'

CBItemList = class(ItemList)

function CBItemList:add(i, item)
	if not item then i, item = nil, i end
	if type(item) == 'string' then
		local s = item
		item = COMBOBOXEXITEM()
		item.text = wcs(s)
	end
	item.i = i or 0
	item.selected_image = item.selected_image or item.image
	item.overlay_image = item.overlay_image or item.image
	ComboBoxEx_InsertItem(self.hwnd, item)
end

function CBItemList:remove(i)
	ComboBox_DeleteItem(self.hwnd, i)
end

function CBItemList:set(i, item)
	if type(item) == 'string' then
		item = COMBOBOXEXITEM()
		item.text = wcs(item)
	end
	item.i = i
	item.selected_image = item.selected_image or item.image
	item.overlay_image = item.overlay_image or item.image
	ComboBoxEx_SetItem(self.hwnd, item)
end

function CBItemList:get(i)
	self.__item = COMBOBOXEXITEM(self.__item)
	COMBOBOXEXITEM:clearmask(self.__item)
	self.__item.i = i
	ComboBoxEx_GetItem(self.hwnd, self.__item)
	return self.__item
end

function CBItemList:get_count()
	return ComboBox_GetCount(self.hwnd)
end

--for ownerdraw lists only
function CBItemList:set_height(i, h) ComboBox_SetItemHeight(self.hwnd, i, h) end
function CBItemList:get_height(i) return ComboBox_GetItemHeight(self.hwnd, i) end


ComboBox = subclass({
	__style_bitmask = bitmask{
		tabstop = WS_TABSTOP,
		type = {
			simple = CBS_SIMPLE,
			dropdown = CBS_DROPDOWN,
			dropdownlist = CBS_DROPDOWNLIST,
		},
		autohscroll = CBS_AUTOHSCROLL,
		vscroll = CBS_DISABLENOSCROLL,
		fixedheight = CBS_NOINTEGRALHEIGHT,
		sort = CBS_SORT,
		case = {
			normal = 0,
			upper = CBS_UPPERCASE,
			lower = CBS_LOWERCASE,
		},
	},
	__style_ex_bitmask = bitmask{ --these don't work well with CBS_SIMPLE says MS!
		no_edit_image = CBES_EX_NOEDITIMAGE,
		no_edit_image2 = CBES_EX_NOEDITIMAGEINDENT,
		path_word_break = CBES_EX_PATHWORDBREAKPROC,
		no_size_limit = CBES_EX_NOSIZELIMIT,
		case_sensitive = CBES_EX_CASESENSITIVE,
	},
	__defaults = {
		tabstop = true,
		type = 'simple',
		autohscroll = true,
		case = 'normal',
		w = 100, h = 100,
	},
	__init_properties = {'text', 'selected_index'},
	__wm_command_handler_names = index{
		on_memory_error = CBN_ERRSPACE,
		on_selection_change = CBN_SELCHANGE,
		on_double_click = CBN_DBLCLK,
		on_focus = CBN_SETFOCUS,
		on_blur = CBN_KILLFOCUS,
		on_edit_change = CBN_EDITCHANGE,
		on_edit_update = CBN_EDITUPDATE,
		on_dropdown = CBN_DROPDOWN,
		on_closeup = CBN_CLOSEUP,
		on_select = CBN_SELENDOK,
		on_cancel = CBN_SELENDCANCEL,
	},
}, Control)

function ComboBox:__before_create(info, args)
	ComboBox.__index.__before_create(self, info, args)
	args.class = WC_COMBOBOXEX
	args.text = info.text --ignored by CreateWindowEx; solved with __init_properies.
	--args.style_ex = bit.bor(args.style_ex, WS_EX_COMPOSITED)
end

function ComboBox:__after_create(info, args)
	ComboBox.__index.__after_create(self, info, args)
	self.items = CBItemList(self, info.items)
end

function ComboBox:set_image_list(iml)
	ComboBoxEx_SetImageList(self.hwnd, iml.himl)
end
function ComboBox:get_image_list()
	local himl = ComboBoxEx_GetImageList(self.hwnd)
	return ImageLists:find(himl) or ImageList(himl)
end

function ComboBox:set_limit(limit) ComboBox_LimitText(self.hwnd, limit) end

function ComboBox:reset() ComboBox_Reset(self.hwnd) end

function ComboBox:set_item_height(height) ComboBox_SetItemHeight(self.hwnd, 'list', height) end
function ComboBox:get_item_height() ComboBox_GetItemHeight(self.hwnd, 'list') end

function ComboBox:set_edit_height(height) ComboBox_SetItemHeight(self.hwnd, 'edit', height) end
function ComboBox:get_edit_height() ComboBox_GetItemHeight(self.hwnd, 'edit') end

function ComboBox:set_edit_selection_indices(t) ComboBox_SetEditSel(self.hwnd, unpack(t,1,2)) end
function ComboBox:get_edit_selection_indices() return {ComboBox_GetEditSel(self.hwnd)} end

function ComboBox:set_dropped_down(show) ComboBox_ShowDropdown(self.hwnd, show) end
function ComboBox:get_dropped_down() return ComboBox_DroppedDown(self.hwnd) end

function ComboBox:set_dropped_width(w) ComboBox_SetDroppedWidth(self.hwnd, w) end
function ComboBox:get_dropped_width() return ComboBox_GetDroppedWidth(self.hwnd) end

function ComboBox:set_selected_index(i) ComboBox_SetCurSel(self.hwnd, i) end
function ComboBox:get_selected_index() return ComboBox_GetCurSel(self.hwnd) end
function ComboBox:get_selected() return self.items:get(self:get_selected_index()) end

--showcase

if not ... then
	require'winapi.showcase'
	local window = ShowcaseWindow{w=300,h=200}
	local cb1 = ComboBox{parent = window, x = 10, y = 10, type = 'dropdownlist'}
	cb1.image_list = ShowcaseImageList()
	cb1.items:add{text = 'Option #1', image = 5}
	cb1.items:add{text = 'Option #2'}
	cb1.items:add{text = 'Option #3 (2nd option is gone)',
							image = 1, selected_image = 2, overlay_image = 3}
	cb1.items:remove(2)
	assert(cb1.items.count == 2)
	print(cb1.items:get(2).text)
	print(cb1.items:get(1).text)
	cb1.selected_index = 1
	cb1.dropped_width = 160
	cb1.dropped_down = true
	assert(cb1.dropped_down)
	cb1.dropped_down = false

	cb2 = ComboBox{parent = window, x = 10, y = 40, h = 80, type = 'dropdown', text = 'dude'}
	cb2.items:add'Option #1'
	cb2.items:add'Option #2'

	cb3 = ComboBox{parent = window, x = 120, y = 10, h = 80,
						type = 'simple', vscroll = false, autohscroll = true}
	cb3.image_list = ShowcaseImageList()
	cb3.items:add{text = 'Option #1', image = 1}
	cb3.items:add{text = 'Option #2', image = 3, overlay_image = 4}
	cb3.items:add{text = 'Option #3', image = 3, overlay_image = 4}
	cb3.items:add{text = 'Option #4', image = 3, overlay_image = 4}
	cb3.edit_height = 12
	cb3.item_height = 14

	MessageLoop()
end

