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

class BigList {
protected:
	HWND	m_hwnd ;
	HWND	m_hwndParent ;	/* コントロールの親ウィンドウ */
	WORD	m_idCtrl ;		/* コントロールの識別番号 */
	DWORD	m_dwChar ;		/* 半角文字の高さ */
	DWORD	m_dwLine ;		/* 表示できる行数 */
	BOOL	m_bFocus ;		/* フォーカスを持っている場合*真* */
	BOOL	m_bPush ;		/* ボタンを押下中の場合*真* */
	BOOL	m_bDblClk ;		/* シングルクリックされた場合*真* */
	BOOL	m_bUseDblClk ;	/* ダブルクリックで確定する場合*真* */

	int		(*m_pProc)( int ln, const BYTE **buf, int *len ) ;
	int		(*m_pSpaceProc)( int ln ) ;
	DWORD	m_dwMax ;		/* リストの個数 */
	DWORD	m_dwTop ;		/* 表示中の先頭行 */
	DWORD	m_dwCur ;		/* カーソル行 */
	DWORD	m_dwLast ;		/* 直前のカーソル行 */

	DWORD	m_dwCurY ;
	DWORD	m_dwCurH ;

	DWORD	m_dwKeyMask ;	/* キー入力マスク */

	BOOL	MouseSub( LPARAM lParam, int *dir ) ;
	BOOL	CheckMask( DWORD mask ) const { return m_dwKeyMask & mask ; }
	BOOL	CheckKeyMask( int nVirtKey ) const ;

public:
	BigList() ;
	~BigList() ;

	BOOL	Create() { return FALSE ; }

	void	WMCreate( HWND hWnd, LPCREATESTRUCT lpcs ) ;
	void	WMSetFocus() ;
	void	WMKillFocus( HWND hWnd ) ;
	void	WMMouseDown( WPARAM wParam, LPARAM lParam ) ;
	void	WMMouseMove( WPARAM wParam, LPARAM lParam ) ;
	void	WMMouseUp( WPARAM wParam, LPARAM lParam ) ;
	void	WMMouseDblClk( WPARAM wParam, LPARAM lParam ) ;
	void	WMPaint() ;
	void	WMChar( TCHAR c, LONG keydata ) ;
	BOOL	WMSysChar( TCHAR c, LONG keydata ) ;
	void	WMKeyDown( int nVirtKey, LONG lKeyData ) ;
	LRESULT	WMCommand( HWND hWnd, UINT msg, WPARAM wp, LPARAM lp ) ;
	void	WMVScroll( WPARAM wParam, LPARAM lParam ) ;
	void	WMSize( DWORD fwSize, WORD nWidth, WORD nHeight ) ;

	void	SetScrollPos() const ;
	void	DrawLines( HDC hDC, DWORD from, DWORD to ) const ;
	void	ChangeTop( DWORD oldTop, DWORD newTop ) ;
	void	ShowCursor( HDC hDC ) ;
	void	HideCursor( HDC hDC ) ;
	void	ShowCursor() ;
	void	HideCursor() ;
	void	KeyDownSub( int nVirtKey, BOOL fShift, BOOL fControl ) ;
	inline	void	KeyEnter() const ;
	inline	void	KeyESC() const ;
	inline	void	KeyTAB( BOOL fShift ) const ;
	void	KeyHome() ;
	void	KeyEnd() ;
	void	KeyUp() ;
	void	KeyDown() ;
	void	KeyPrior() ;
	void	KeyNext() ;
	void	EnsureFocusVisible() ;
	void	SetProc( int (*proc)( int ln, const BYTE **buf, int *len ) ) ;
	void	SetSpaceProc( int (*proc)( int ln ) ) ;
	DWORD	GetCurSel() const ;
	void	SetCurSel( DWORD index ) ;
	void	SetKeyMask( DWORD mask ) { m_dwKeyMask = mask ; }
	int		FindString( DWORD indexStart, LPCTSTR lpszFind ) const ;
	void	SetDblClk( BOOL bDblClk ) { m_bUseDblClk = bDblClk ; }
	DWORD	GetMaxLine() const { return m_dwLine ; }

	friend	LRESULT CALLBACK	BigListWndProc( HWND hWnd,  UINT msg, WPARAM wParam, LPARAM lParam ) ;
} ;
typedef	BigList	*PBigList ;

BigList::BigList()
{
	m_dwChar = GetFontH() ;
	m_pProc = 0 ;
	m_pSpaceProc = 0 ;
	m_dwMax = m_dwTop = m_dwCur = 0 ;
	m_dwLast = (DWORD) -1 ;
	m_dwLine = 0 ;
	m_bFocus = FALSE ;
	m_bPush = FALSE ;
	m_dwKeyMask = 0xFFFF ;
	m_bUseDblClk = FALSE ;
}

BigList::~BigList()
{
}

void
BigList::WMCreate( HWND hWnd, LPCREATESTRUCT lpcs )
{
	RECT	rect ;

	m_hwnd = hWnd ;
	m_hwndParent = lpcs->hwndParent ;
	m_idCtrl = (WORD) lpcs->hMenu ;
	/* 一度に表示できる行数を求める */
	GetClientRect( m_hwnd, &rect ) ;
	m_dwLine = rect.bottom - rect.top + 1 - 2 ;
	m_dwLine /= m_dwChar ;
}

void
BigList::WMSetFocus()
{
	m_bFocus = TRUE ;
	HideCursor() ;
	ShowCursor() ;
}

void
BigList::WMKillFocus( HWND hWnd )
{
	m_bFocus = FALSE ;
	HideCursor() ;
	ShowCursor() ;
}

BOOL
BigList::MouseSub( LPARAM lParam, int *dir )
{
	RECT	rect ;
	DWORD	newCur = 0 ;
	WORD	xPos = LOWORD( lParam ) ;
	short	yPos = (short) HIWORD( lParam ) ;

	if ( dir ) {
		*dir = 0 ;
	}
	if ( GetFocus() != m_hwnd ) {
		SetFocus( m_hwnd ) ;
	}
	GetClientRect( m_hwnd, &rect ) ;
	if ( xPos >= rect.right ) {
		return FALSE ;
	} else if ( yPos < 1 ) {
		if ( dir ) {
			*dir = -1 ;
		}
		return FALSE ;
	}
	newCur = (yPos - 1) / m_dwChar + m_dwTop ;
	if ( newCur < m_dwMax && newCur < m_dwTop + m_dwLine ) {
		m_dwCur = newCur ;
		EnsureFocusVisible() ;
		return TRUE ;
	} else {
		if ( dir ) {
			*dir = 1 ;
		}
	}
	return FALSE ;
}

void
BigList::WMMouseDown( WPARAM wParam, LPARAM lParam )
{
	if ( MouseSub( lParam, NULL ) ) {
		m_bPush = TRUE ;
		m_bDblClk = FALSE ;
		SetCapture( m_hwnd ) ;
	}
}

void
BigList::WMMouseMove( WPARAM wParam, LPARAM lParam )
{
	if ( m_bPush ) {
		int		dir ;
		if ( !MouseSub( lParam, &dir ) && dir ) {
			if ( dir < 0 ) {
				KeyUp() ;
			} else {
				KeyDown() ;
			}
			EnsureFocusVisible() ;
		}
	}
}

void
BigList::WMMouseUp( WPARAM wParam, LPARAM lParam )
{
	if ( m_bPush ) {
		m_bPush = FALSE ;
		if ( MouseSub( lParam, NULL ) ) {
			if ( m_bUseDblClk ) {
				m_bDblClk = TRUE ;
			} else {
				KeyEnter() ;
			}
		}
	}
	ReleaseCapture() ;
}

void
BigList::WMMouseDblClk( WPARAM wParam, LPARAM lParam )
{
	if ( m_bDblClk ) {
		m_bDblClk = FALSE ;
		KeyEnter() ;
	}
}

void
BigList::WMPaint()
{
	PAINTSTRUCT	ps ;
	HDC			hDC ;
	int			len ;
	DWORD		i, h ;
	RECT		rect ;
	const BYTE	*ptr ;
	CHAR		sjis[ 128 ] ;
	TCHAR		unicode[ 128 ] ;

	hDC = ::BeginPaint( m_hwnd, &ps ) ;
	GetClientRect( m_hwnd, &rect ) ;
	m_dwCurY = m_dwCurH = 0 ;
	if ( m_pProc ) {
		rect.top += 1 ;		rect.left += 1 ;	rect.right -= 1 ;
		h = rect.bottom - rect.top + 1 ;
		for ( i = m_dwTop ; ; i ++ ) {
			if ( (*m_pProc)( (int) i, &ptr, &len ) == -1 ) {
				/* リストの範囲外になった場合 */
				break ;
			} else if ( h <= m_dwChar ) {
				/* 画面に入りきらない場合 */
				break ;
			}
			h -= m_dwChar ;
			/* 必要な部分だけ取り出してUnicode変換する */
			memcpy( sjis, ptr, len ), sjis[ len ] = 0 ;
			sjis2unicode( (LPBYTE) sjis, unicode, sizeof unicode ) ;
			rect.bottom = rect.top + m_dwChar - 1 ;
			/* 行表示を行う */
			KDrawText( hDC, unicode, -1, &rect, 0 ) ;
			if ( i == m_dwCur ) {
				m_dwCurH = m_bFocus ? m_dwChar : 2 ;
				m_dwCurY = rect.top + (m_dwChar - m_dwCurH) ;
				/* カーソル位置だった場合 */
				PatBlt( hDC, 0, m_dwCurY, rect.right + 1, m_dwCurH, DSTINVERT ) ;
			}
			rect.top += m_dwChar ;
		}
	}
	::EndPaint( m_hwnd, &ps ) ;
}

void
BigList::WMChar( TCHAR chCharCode, LONG lKeyData )
{
	if ( chCharCode == TEXT(' ') && m_pSpaceProc ) {
		if ( (*m_pSpaceProc)( m_dwCur ) ) {
			::InvalidateRect( m_hwnd, NULL, TRUE ) ;
		}
	} else {
		PostMessage( m_hwndParent, WM_COMMAND, MAKEWPARAM( m_idCtrl, BLN_CHAR ), chCharCode ) ;
	}
}

BOOL
BigList::WMSysChar( TCHAR chCharCode, LONG lKeyData )
{
	return FALSE ;
}

BOOL
BigList::CheckKeyMask( int nVirtKey ) const
{
	switch ( nVirtKey ) {
	case VK_RETURN:		return CheckMask( BL_MASK_RETURN )  ;
	case VK_ESCAPE:		return CheckMask( BL_MASK_ESCAPE )  ;
	case VK_TAB:		return CheckMask( BL_MASK_TAB )  ;
	case VK_HOME:		return CheckMask( BL_MASK_HOME )  ;
	case VK_END:		return CheckMask( BL_MASK_END )  ;
	case VK_UP:			return CheckMask( BL_MASK_UP )  ;
	case VK_DOWN:		return CheckMask( BL_MASK_DOWN )  ;
	case VK_LEFT:		return CheckMask( BL_MASK_LEFT )  ;
	case VK_PRIOR:		return CheckMask( BL_MASK_PRIOR )  ;
	case VK_RIGHT:		return CheckMask( BL_MASK_RIGHT )  ;
	case VK_NEXT:		return CheckMask( BL_MASK_NEXT )  ;
	}
	return TRUE ;
}

void
BigList::KeyDownSub( int nVirtKey, BOOL fShift, BOOL fControl )
{
	switch ( nVirtKey ) {
	case VK_RETURN:		KeyEnter() ;		break ;
	case VK_ESCAPE:		KeyESC() ;			break ;
	case VK_TAB:		KeyTAB( fShift ) ;	break ;
	case VK_HOME:		KeyHome() ;			break ;
	case VK_END:		KeyEnd() ;			break ;
	case VK_UP:			KeyUp() ;			break ;
	case VK_DOWN:		KeyDown() ;			break ;
	case VK_LEFT:
	case VK_PRIOR:		KeyPrior() ;		break ;
	case VK_RIGHT:
	case VK_NEXT:		KeyNext() ;			break ;
	default:								return ;
	}
	EnsureFocusVisible() ;
}

void
BigList::WMKeyDown( int nVirtKey, LONG lKeyData )
{
	BOOL	fShift   = 0x80 & GetKeyState( VK_SHIFT ) ;
	BOOL	fControl = 0x80 & GetKeyState( VK_CONTROL ) ;

	if ( CheckKeyMask( nVirtKey ) ) {
		KeyDownSub( nVirtKey, fShift, fControl ) ;
	} else {
		PostMessage( m_hwndParent, WM_COMMAND, MAKEWPARAM( m_idCtrl, (BLN_KEYDOWN|nVirtKey) ), (LPARAM) m_hwnd ) ;
	}
}

LRESULT
BigList::WMCommand( HWND hWnd, UINT msg, WPARAM wp, LPARAM lp )
{
	return 0 ;
}

void
BigList::WMVScroll( WPARAM wParam, LPARAM lParam )
{
	int		nScrollCode = (int) LOWORD(wParam) ;
	int		nPos = (short int) HIWORD(wParam) ;
	DWORD	newTop = m_dwTop ;

	switch ( nScrollCode ) {
	case SB_TOP:
		newTop = 0 ;
		break ;
	case SB_BOTTOM:
		newTop = m_dwMax >= m_dwLine ? m_dwMax - m_dwLine : 0 ;
		break ;
	case SB_LINEDOWN:
		if ( m_dwTop + m_dwLine >= m_dwMax ) {
			return ;
		} else {
			newTop = m_dwTop + 1 ;
		}
		break ;
	case SB_LINEUP:
		if ( m_dwTop ) {
			newTop = m_dwTop - 1 ;
		} else {
			return ;
		}
		break ;
	case SB_PAGEDOWN:
		newTop = m_dwTop + m_dwLine * 2 - 1 >= m_dwMax ? m_dwMax - m_dwLine : m_dwTop + m_dwLine - 1 ;
		break ;
	case SB_PAGEUP:
		newTop = m_dwTop < m_dwLine - 1 ? 0 : m_dwTop - m_dwLine + 1 ;
		break ;
	case SB_THUMBPOSITION:
		if ( nPos < (int) m_dwMax ) {
			newTop = nPos ;
		} else {
			return ;
		}
		break ;
	default:
		return ;
	}
	ChangeTop( m_dwTop, newTop ) ;
}

void
BigList::WMSize( DWORD fwSize, WORD nWidth, WORD nHeight )
{
	RECT	rect ;

	/* 一度に表示できる行数を求める */
	GetClientRect( m_hwnd, &rect ) ;
	m_dwLine = rect.bottom - rect.top + 1 - 2 ;
	m_dwLine /= m_dwChar ;
}

/*
 * 垂直スクロールバー制御
 */
void
BigList::SetScrollPos() const
{
	SCROLLINFO	si ;

	memset( &si, 0, sizeof si ) ;
	si.cbSize = sizeof si ;
	si.fMask = SIF_POS|SIF_RANGE ;
	si.nMin = 0 ;
	si.nMax = m_dwMax >= m_dwLine ? m_dwMax - m_dwLine : 0 ;
	si.nPos = m_dwTop ;
	SetScrollInfo( m_hwnd, SB_VERT, &si, TRUE ) ;
}

/*
 * 指定された範囲の行を描く
 */
void
BigList::DrawLines( HDC hDC, DWORD from, DWORD to ) const
{
	DWORD		i ;
	int			len ;
	RECT		rect ;
	const BYTE	*ptr ;
	CHAR		sjis[ 128 ] ;
	TCHAR		unicode[ 128 ] ;

	GetClientRect( m_hwnd, &rect ) ;
	rect.top = from * m_dwChar + 1 ;
	for ( i = from ; i <= to ; i ++ ) {
		if ( (*m_pProc)( (int) (i + m_dwTop), &ptr, &len ) == -1 ) {
			/* リストの範囲外になった場合 */
			break ;
		}
		/* 必要な部分だけ取り出してUnicode変換する */
		memcpy( sjis, ptr, len ), sjis[ len ] = 0 ;
		sjis2unicode( (LPBYTE) sjis, unicode, sizeof unicode ) ;
		rect.bottom = rect.top + m_dwChar ;
		FillRect( hDC, &rect, (HBRUSH) GetStockObject( WHITE_BRUSH ) ) ;
		rect.bottom = rect.top + m_dwChar - 1 ;
		/* 行表示を行う */
		KDrawText( hDC, unicode, -1, &rect, 0 ) ;
		rect.top += m_dwChar ;
	}
	for ( ; i <= to ; i ++ ) {
		rect.bottom = rect.top + m_dwChar ;
		FillRect( hDC, &rect, (HBRUSH) GetStockObject( WHITE_BRUSH ) ) ;
	}
}

/*
 * 先頭行を変更する処理を行う
 */
void
BigList::ChangeTop( DWORD oldTop, DWORD newTop )
{
	HDC		hDC ;
	RECT	clip, scroll ;

	m_dwTop = newTop ;
	::GetClientRect( m_hwnd, &clip ) ;
	clip.top ++ ;
	clip.bottom = clip.top + m_dwChar * m_dwLine ; //- 1 ;
	scroll = clip ;
	if ( oldTop == newTop ) {
		return ;
	} else if ( oldTop + 1 == newTop ) {
		/* 上スクロールの場合 */
		hDC = ::GetDC( m_hwnd ) ;
		HideCursor( hDC ) ;
		scroll.top += m_dwChar ;
		::ScrollWindowEx( m_hwnd, 0, - (int) m_dwChar, &scroll, &clip, NULL, NULL, SW_ERASE ) ;
		DrawLines( hDC, m_dwLine - 1, m_dwLine - 1 ) ;
		ShowCursor( hDC ) ;
		::ReleaseDC( m_hwnd, hDC ) ;
	} else if ( oldTop == newTop + 1 ) {
		/* 下スクロールの場合 */
		hDC = ::GetDC( m_hwnd ) ;
		HideCursor( hDC ) ;
		scroll.bottom -= m_dwChar ;
		::ScrollWindowEx( m_hwnd, 0, m_dwChar, &scroll, &clip, NULL, NULL, SW_ERASE ) ;
		DrawLines( hDC, 0, 0 ) ;
		ShowCursor( hDC ) ;
		::ReleaseDC( m_hwnd, hDC ) ;
	} else {
		/* 全体を描画しなおす場合 */
		::InvalidateRect( m_hwnd, NULL, TRUE ) ;
	}
	SetScrollPos() ;
}

/*
 * カーソル行を描く
 */
void
BigList::ShowCursor( HDC hDC )
{
	RECT	rect ;

	if ( m_dwCur >= m_dwTop && m_dwCur <= m_dwTop + m_dwLine - 1 ) {
		GetClientRect( m_hwnd, &rect ) ;
		m_dwCurH = m_bFocus ? m_dwChar : 2 ;
		m_dwCurY = (m_dwCur - m_dwTop + 1) * m_dwChar - m_dwCurH + 1 ;
		PatBlt( hDC, 0, m_dwCurY, rect.right, m_dwCurH, DSTINVERT ) ;
	} else {
		m_dwCurY = m_dwCurH = 0 ;
	}
}

/*
 * カーソル行を消す
 */
void
BigList::HideCursor( HDC hDC )
{
	RECT	rect ;

	if ( !m_dwCurH ) {
		return ;
	}
	GetClientRect( m_hwnd, &rect ) ;
	PatBlt( hDC, 0, m_dwCurY, rect.right, m_dwCurH, DSTINVERT ) ;
	m_dwCurY = m_dwCurH = 0 ;
}

/*
 * カーソル行を描く
 */
void
BigList::ShowCursor()
{
	HDC		hDC = GetDC( m_hwnd ) ;
	ShowCursor( hDC ) ;
	ReleaseDC( m_hwnd, hDC ) ;
}

/*
 * カーソル行を消す
 */
void
BigList::HideCursor()
{
	HDC		hDC = GetDC( m_hwnd ) ;
	HideCursor( hDC ) ;
	ReleaseDC( m_hwnd, hDC ) ;
}

/*
 * Enterキーが押された場合
 */
void
BigList::KeyEnter() const
{
	SendMessage( m_hwndParent, WM_COMMAND, MAKEWPARAM( m_idCtrl, BLN_ENTER ), (LPARAM) m_hwnd ) ;
}

/*
 * ESCキーが押された場合
 */
void
BigList::KeyESC() const
{
	SendMessage( m_hwndParent, WM_COMMAND, MAKEWPARAM( m_idCtrl, BLN_ESC ), (LPARAM) m_hwnd ) ;
}

/*
 * TABキーが押された場合
 */
void
BigList::KeyTAB( BOOL fShift ) const
{
	WORD	cmd = fShift ? BLN_STAB : BLN_TAB ;
	SendMessage( m_hwndParent, WM_COMMAND, MAKEWPARAM( m_idCtrl, cmd ), (LPARAM) m_hwnd ) ;
}

/*
 * リストの先頭に移動する
 */
void
BigList::KeyHome()
{
	m_dwCur = 0 ;
}

/*
 * リストの最後に移動する
 */
void
BigList::KeyEnd()
{
	if ( !m_pProc ) {
		return ;
	}
	m_dwCur = m_dwMax ? m_dwMax - 1 : 0 ;
}

/*
 * 一行上に移動する
 */
void
BigList::KeyUp()
{
	if ( m_dwCur ) {
		m_dwCur -- ;
	}
}

/*
 * 一行下に移動する
 */
void
BigList::KeyDown()
{
	if ( m_dwCur + 1 < m_dwMax ) {
		m_dwCur ++ ;
	}
}

/*
 * 一ページ前に移動する
 */
void
BigList::KeyPrior()
{
	if ( m_dwCur >= m_dwLine - 1 ) {
		m_dwCur -= m_dwLine - 1 ;
	} else {
		m_dwCur = 0 ;
	}
}

/*
 * 一ページ後に移動する
 */
void
BigList::KeyNext()
{
	if ( m_dwCur + m_dwLine - 1 < m_dwMax ) {
		m_dwCur += m_dwLine - 1 ;
	} else {
		m_dwCur = m_dwMax - 1 ;
	}
}

/*
 * カーソル行が画面に現れるようにする
 */
void
BigList::EnsureFocusVisible()
{
	BOOL	fShow = FALSE ;
	BOOL	fCursor = FALSE ;
	DWORD	line, oldTop = m_dwTop ;

	if ( m_dwLast != m_dwCur ) {
		HideCursor() ;
		fCursor = TRUE ;
		PostMessage( m_hwndParent, WM_COMMAND, MAKEWPARAM( m_idCtrl, BLN_CHANGE ), (LPARAM) m_hwnd ) ;
	}
	if ( m_dwCur < m_dwTop || m_dwCur > m_dwTop + m_dwLine - 1 ) {
		/* 表示範囲を超えている場合 */
		if ( m_dwLast < m_dwTop || m_dwLast > m_dwTop + m_dwLine - 1 ) {
			/* 前回の位置も表示範囲を超えていた場合 */
			line = m_dwLine / 2 ;
		} else {
			/* 画面上の行位置を求める */
			line = m_dwLast - m_dwTop ;
		}
		if ( m_dwCur < line ) {
			/* リストの先頭にある場合 */
			m_dwTop = 0 ;
		} else {
			m_dwTop = m_dwCur - line ;
		}
		if ( m_dwTop + m_dwLine >= m_dwMax ) {
			m_dwTop = m_dwMax >= m_dwLine ? m_dwMax - m_dwLine : 0 ;
		}
		fShow = TRUE ;
	}
	if ( fShow ) {
		ChangeTop( oldTop, m_dwTop ) ;
		fCursor = FALSE ;
	}
	if ( fCursor ) {
		ShowCursor() ;
	}
	m_dwLast = m_dwCur ;
}

/*
 * 項目取得用プロシージャを設定する
 */
void
BigList::SetProc( int (*proc)( int ln, const BYTE **buf, int *len ) )
{
	m_pProc = proc ;
	m_dwMax = m_pProc ? (DWORD) (*m_pProc)( -1, 0, 0 ) : 0 ;
	m_dwTop = m_dwCur = 0 ;
	m_dwLast = (DWORD) -1 ;
	EnsureFocusVisible() ;
	::InvalidateRect( m_hwnd, NULL, TRUE ) ;
	SetScrollPos() ;
}

/*
 * スペース処理用プロシージャを設定する
 */
void
BigList::SetSpaceProc( int (*proc)( int ln ) )
{
	m_pSpaceProc = proc ;
}

/*
 * カーソル行を得る
 */
DWORD
BigList::GetCurSel() const
{
	return m_dwCur ;
}

/*
 * カーソル行を設定する
 */
void
BigList::SetCurSel( DWORD index )
{
	if ( index >= m_dwMax ) {
		return ;
	}
	m_dwCur = index ;
	EnsureFocusVisible() ;
}

/*
 * 文字列を検索する
 */
int
BigList::FindString( DWORD indexStart, LPCTSTR lpszFind ) const
{
	const BYTE	*ptr ;
	BYTE		sjis[ 128 ] ;
	int			len, lenFind ;
	TCHAR		unicode[ 128 ] ;

	if ( indexStart >= m_dwMax ) {
		return -1 ;
	}
	lenFind = _tcslen( lpszFind ) ;
	for ( ; indexStart < m_dwMax ; indexStart ++ ) {
		if ( (*m_pProc)( (int) indexStart, &ptr, &len ) != -1 ) {
			memcpy( sjis, ptr, len ), sjis[ len ] = 0 ;
			sjis2unicode( sjis, unicode, sizeof unicode ) ;
			if ( !_tcsnicmp( lpszFind, unicode, lenFind ) ) {
				return (int) indexStart ;
			}
		}
	}
	return -1 ;
}

BOOL
BigListRegisterClass( HINSTANCE hInst )
{
	WNDCLASS	wc ;

	wc.style         = CS_DBLCLKS ;
	wc.lpfnWndProc   = (WNDPROC) BigListWndProc ;
	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_BIGLIST ;
	return ::RegisterClass( &wc ) ;
}

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

	if ( msg == WM_CREATE ) {
		LPCREATESTRUCT	lpStruct = (LPCREATESTRUCT) lParam ;
		pWindow = new BigList() ;
		SetWindowLong( hWnd, 0, (LONG) pWindow ) ;
		pWindow->WMCreate( hWnd, lpStruct ) ;
		return 0 ;
	}
	pWindow = (PBigList) 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_SETFOCUS:
		pWindow->WMSetFocus() ;
		return DefWindowProc( hWnd, msg, wParam, lParam ) ;
	case WM_KILLFOCUS:
		pWindow->WMKillFocus( (HWND) wParam ) ;
		return DefWindowProc( hWnd, msg, wParam, lParam ) ;
	case WM_COMMAND:
		return pWindow->WMCommand( hWnd, msg, wParam, lParam ) ;
	case WM_PAINT:			pWindow->WMPaint() ;		break ;
	case WM_CHAR:			pWindow->WMChar( (TCHAR) wParam, lParam ) ;		break ;
	case WM_SYSCHAR:
		if ( !pWindow->WMSysChar( (TCHAR) wParam, lParam ) ) {
			DefWindowProc( hWnd, msg, wParam, lParam ) ;
		}
		break ;
	case WM_KEYDOWN:
		pWindow->WMKeyDown( (int) wParam, lParam ) ;
		break ;
	case WM_LBUTTONDOWN:	pWindow->WMMouseDown( wParam, lParam ) ;		break ;
	case WM_LBUTTONUP:		pWindow->WMMouseUp( wParam, lParam ) ;			break ;
	case WM_MOUSEMOVE:		pWindow->WMMouseMove( wParam, lParam ) ;		break ;
	case WM_LBUTTONDBLCLK:	pWindow->WMMouseDblClk( wParam, lParam ) ;	break ;
	case WM_VSCROLL:		pWindow->WMVScroll( wParam, lParam ) ;			break ;
	case WM_SIZE:
		pWindow->WMSize( wParam, LOWORD(lParam), HIWORD(lParam) ) ;
		break ;

//	case WM_GETDLGCODE:		return DLGC_WANTARROWS|DLGC_WANTTAB ;
	case WM_GETDLGCODE:		return DLGC_WANTALLKEYS ;
	case BLM_SETPROC:		pWindow->SetProc( (int(*)(int,const BYTE**, int*)) lParam ) ;	break ;
	case BLM_GETCURSEL:		return pWindow->GetCurSel() ;
	case BLM_SETCURSEL:		pWindow->SetCurSel( (DWORD) wParam ) ;			break ;
	case BLM_SETSPACEPROC:	pWindow->SetSpaceProc( (int(*)(int)) lParam ) ;	break ;
	case BLM_SETKEYMASK:	pWindow->SetKeyMask( (DWORD) lParam ) ;			break ;
	case BLM_FINDSTRING:	return pWindow->FindString( (DWORD) wParam, (LPCTSTR) lParam ) ;
	case BLM_SETDBLCLK:		pWindow->SetDblClk( (BOOL) wParam ) ;			break ;
	case BLM_GETMAXLINE:	return pWindow->GetMaxLine() ;
	default:
		return DefWindowProc( hWnd, msg, wParam, lParam ) ;
	}
	return 0 ;
}
