#define	STRICT
#include	<windows.h>
#include	<commctrl.h>
#include	<tchar.h>
#include	"controls.h"

extern "C" {
	LRESULT CALLBACK	ListBoxWndProc( HWND hWnd,  UINT msg, WPARAM wParam, LPARAM lParam ) ;
} ;

class ListBox {
protected:
	HWND	m_hWnd ;
	HWND	m_hWndList ;
	HWND	m_hWndParent ;
	WORD	m_wID ;

public:
	ListBox() ;
	~ListBox() ;

	BOOL	Create() { return FALSE ; }

	void	WMCreate( HWND hWnd, LPCREATESTRUCT lpStruct ) ;
	void	WMSetFocus() ;
	void	WMNotify( WPARAM wParam, LPARAM lParam ) ;
	int		WMVKeyToItem( WPARAM wParam, LPARAM lParam ) ;
	void	WMSize( DWORD fwSize, WORD nWidth, WORD nHeight ) ;

	friend	LRESULT CALLBACK	ListBoxWndProc( HWND hWnd,  UINT msg, WPARAM wParam, LPARAM lParam ) ;
} ;
typedef	ListBox	*PListBox ;

ListBox::ListBox()
{
}

ListBox::~ListBox()
{
}

void
ListBox::WMCreate( HWND hWnd, LPCREATESTRUCT lpStruct )
{
	RECT		rect ;

	m_hWnd = hWnd ;
	m_hWndParent = GetParent( hWnd ) ;
	m_wID = (WORD) lpStruct->hMenu ;
    GetClientRect( hWnd, &rect ) ;
	m_hWndList = CreateWindow( TEXT("LISTBOX"),
                        TEXT(""),
                        WS_VISIBLE|WS_CHILD|WS_VSCROLL|
						LBS_NOTIFY|LBS_WANTKEYBOARDINPUT|
						LBS_SORT|LBS_DISABLENOSCROLL|LBS_NOINTEGRALHEIGHT|LBS_USETABSTOPS|
						(lpStruct->style & ~(WS_BORDER)),
                        1, 1, rect.right - GetSystemMetrics(SM_CXVSCROLL), rect.bottom,
                        hWnd,
                        lpStruct->hMenu,
                        lpStruct->hInstance,
                        NULL ) ;
	if ( !m_hWndList ) {
		return ;
	}
}

void
ListBox::WMSetFocus()
{
	::SetFocus( m_hWndList ) ;
}

void
ListBox::WMNotify( WPARAM wParam, LPARAM lParam )
{
	if ( m_hWndParent ) {
		SendMessage( m_hWndParent, WM_NOTIFY, wParam, lParam ) ;
	}
}

int
ListBox::WMVKeyToItem( WPARAM wParam, LPARAM lParam )
{
	if ( LOWORD(wParam) == VK_RETURN ) {
		if ( m_hWndParent ) {
			SendMessage( m_hWndParent, WM_COMMAND, MAKELONG(m_wID, LBN_DBLCLK), 0 ) ;
		}
	}
	return 0 ;
}

void
ListBox::WMSize( DWORD fwSize, WORD nWidth, WORD nHeight )
{
	HWND	hWndCtrl ;

	hWndCtrl = GetDlgItem( m_hWnd, m_wID ) ;
	SetWindowPos( hWndCtrl, 0, 0, 0, nWidth - 2, nHeight - 2,
				  SWP_NOMOVE|SWP_NOZORDER ) ;
}

BOOL
ListBoxRegisterClass( HINSTANCE hInst )
{
	WNDCLASS	wc ;

	wc.style         = NULL ;
	wc.lpfnWndProc   = (WNDPROC) ListBoxWndProc ;
	wc.cbClsExtra    = 0 ;
	wc.cbWndExtra    = 4 ;
	wc.hInstance     = hInst ;
	wc.hIcon         = NULL ;
	wc.hCursor       = NULL ;
	wc.hbrBackground = (HBRUSH) GetStockObject( WHITE_BRUSH ) ;
	wc.lpszMenuName  = 0 ;
	wc.lpszClassName = CTRL_LISTBOX ;
	return ::RegisterClass( &wc ) ;
}

LRESULT CALLBACK
ListBoxWndProc( HWND hWnd,  UINT msg, WPARAM wParam, LPARAM lParam )
{
	PListBox	pWindow ;

	if ( msg == WM_CREATE ) {
		LPCREATESTRUCT	lpStruct = (LPCREATESTRUCT) lParam ;
		pWindow = new ListBox() ;
		SetWindowLong( hWnd, 0, (LONG) pWindow ) ;
		pWindow->WMCreate( hWnd, lpStruct ) ;
		return 0 ;
	}
	pWindow = (PListBox) GetWindowLong( hWnd, 0 ) ;
	if ( !pWindow ) {
		return DefWindowProc( hWnd, msg, wParam, lParam ) ;
	}
	switch ( msg ) {
	case WM_DESTROY:
		delete pWindow ;
		SetWindowLong( hWnd, 0, (LONG) 0 ) ;
		break ;
	case WM_NOTIFY:
		pWindow->WMNotify( wParam, lParam ) ;
		break ;
	case WM_SETFOCUS:
		pWindow->WMSetFocus() ;
		break ;
	case WM_GETDLGCODE:
		return DLGC_WANTMESSAGE ;
	case WM_SETFONT:
		return SendMessage( pWindow->m_hWndList, msg, wParam, lParam ) ;
	case WM_COMMAND:
		if ( pWindow->m_hWndParent ) {
			return SendMessage( pWindow->m_hWndParent, msg, wParam, lParam ) ;
		}
		break ;
	case WM_VKEYTOITEM:
		if ( pWindow->WMVKeyToItem( wParam, lParam ) < 0 ) {
			break ;
		}
		return DefWindowProc( hWnd, msg, wParam, lParam ) ;
	case WM_SIZE:
		pWindow->WMSize( (DWORD) wParam, LOWORD(lParam), HIWORD(lParam) ) ;
		break ;
	default:
		if ( msg >= LB_ADDSTRING && msg <= LB_MSGMAX ) {
			return SendMessage( pWindow->m_hWndList, msg, wParam, lParam ) ;
		}
		return DefWindowProc( hWnd, msg, wParam, lParam ) ;
	}
	return 0 ;
}
