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

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

class Confirm {
private:
	HWND	m_hWnd ;
	HWND	m_hWndParent ;		/* コントロールの親ウィンドウ */
	WORD	m_idCtrl ;			/* コントロールの識別番号 */
	CHAR	m_sInput[ 128 ] ;	/* 入力文字列 */
	CHAR	m_sFixed[ 128 ] ;	/* 確定文字列 */
	HBRUSH	m_hBrushSel ;		/* 選択範囲のブラシ */

public:
	Confirm() ;
	~Confirm() ;

	inline	void	WMCreate( HWND hWnd, LPCREATESTRUCT lpcs ) ;
	inline	void	WMPaint() ;
	inline	void	WMChar( TCHAR c, LONG keydata ) ;

	inline	DWORD	GetWidth( LPCTSTR unicode ) ;

	inline	void	SetInput( LPCSTR sjis ) ;
	inline	void	SetFixed( LPCSTR sjis ) ;
	inline	void	SetSelColor( COLORREF color ) ;
	inline	BOOL	IsEmpty() const ;
} ;
typedef	Confirm	*PConfirm ;

Confirm::Confirm()
{
	m_sInput[0] = m_sFixed[0] = 0 ;
	m_hBrushSel = CreateSolidBrush( RGB( 128, 128, 128 ) ) ;
}

Confirm::~Confirm()
{
	if ( m_hBrushSel ) {
		DeleteObject( m_hBrushSel ) ;
	}
}

void
Confirm::WMCreate( HWND hWnd, LPCREATESTRUCT lpcs )
{
	m_hWnd = hWnd ;
	m_hWndParent = lpcs->hwndParent ;
	m_idCtrl = (WORD) lpcs->hMenu ;
}

void
Confirm::WMPaint()
{
	PAINTSTRUCT	ps ;
	HDC			hDC ;
	RECT		rect ;
	HBRUSH		hOldBrush ;
	TCHAR		unicode[ 256 ] ;
	DWORD		w1, w2, w3, len ;

	hDC = ::BeginPaint( m_hWnd, &ps ) ;
	GetClientRect( m_hWnd, &rect ) ;
	sjis2unicode( (LPBYTE) m_sFixed, unicode, sizeof unicode ) ;
	len = _tcslen( unicode ) ;
	if ( !*m_sInput ) {
		unicode[ len ++ ] = TEXT('_') ;
		unicode[ len ] = 0 ;
	}
	w1 = GetWidth( unicode ) ;
	sjis2unicode( (LPBYTE) m_sInput, &unicode[ len ], sizeof unicode - (len * sizeof *unicode) ) ;
	w2 = GetWidth( unicode ) - w1 ;
	rect.top += 1 ;		rect.left += 1 ;
	rect.bottom -= 1 ;	rect.right -= 1 ;
	KDrawText( hDC, unicode, -1, &rect, 0 ) ;
	w3 = rect.right - rect.left + 1 ;
	if ( w3 > w1 ) {
		w3 -= w1 ;
		if ( w3 > w2 ) {
			w3 = w2 ;
		}
		hOldBrush = (HBRUSH) SelectObject( hDC, m_hBrushSel ) ;
		PatBlt( hDC, rect.left + w1, rect.top, w3, rect.bottom - rect.top + 1, PATINVERT ) ;
		SelectObject( hDC, hOldBrush ) ;
	}
	::EndPaint( m_hWnd, &ps ) ;
}

void
Confirm::WMChar( TCHAR c, LONG keydata )
{
	if ( m_hWndParent ) {
		SendMessage( m_hWndParent, WM_COMMAND, MAKEWPARAM( m_idCtrl, CONFIRMN_CHAR ), c ) ;
	}
}

DWORD
Confirm::GetWidth( LPCTSTR unicode )
{
	TCHAR	c ;
	DWORD	width, hw, zw ;

	hw = GetFontHW() ;
	zw = GetFontZW() ;
	width = 0 ;
	while ( c = *unicode++ ) {
		width += is_hankaku( c ) ? hw : zw ;
	}
	return width ;
}

void
Confirm::SetInput( LPCSTR sjis )
{
	strcpy( m_sInput, sjis ) ;
	InvalidateRect( m_hWnd, NULL, TRUE ) ;
}

void
Confirm::SetFixed( LPCSTR sjis )
{
	strcpy( m_sFixed, sjis ) ;
	InvalidateRect( m_hWnd, NULL, TRUE ) ;
}

void
Confirm::SetSelColor( COLORREF color )
{
	if ( m_hBrushSel ) {
		DeleteObject( m_hBrushSel ) ;
	}
	m_hBrushSel = CreateSolidBrush( color ) ;
}

BOOL
Confirm::IsEmpty() const
{
	return !*m_sInput && !*m_sFixed ;
}

BOOL
ConfirmRegisterClass( HINSTANCE hInst )
{
	WNDCLASS	wc ;

	wc.style         = NULL ;
	wc.lpfnWndProc   = (WNDPROC) ConfirmWndProc ;
	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_CONFIRM ;
	return ::RegisterClass( &wc ) ;
}

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

	if ( msg == WM_CREATE ) {
		LPCREATESTRUCT	lpStruct = (LPCREATESTRUCT) lParam ;
		pWindow = new Confirm() ;
		SetWindowLong( hWnd, 0, (LONG) pWindow ) ;
		pWindow->WMCreate( hWnd, lpStruct ) ;
		return 0 ;
	}
	pWindow = (PConfirm) GetWindowLong( hWnd, 0 ) ;
	switch ( msg ) {
	case WM_DESTROY:
		delete pWindow ;
		SetWindowLong( hWnd, 0, (LONG) 0 ) ;
		break ;
	case WM_PAINT:
		pWindow->WMPaint() ;
		break ;
	case CONFIRM_SETINPUT:
		pWindow->SetInput( (LPCSTR) lParam ) ;
		break ;
	case CONFIRM_SETFIXED:
		pWindow->SetFixed( (LPCSTR) lParam ) ;
		break ;
	case CONFIRM_SETCOLSEL:
		pWindow->SetSelColor( (COLORREF) lParam ) ;
		break ;
	case CONFIRM_ISEMPTY:
		return pWindow->IsEmpty() ;
		break ;
	case WM_GETDLGCODE:
		return DLGC_WANTCHARS ;
	case WM_CHAR:
		pWindow->WMChar( (TCHAR) wParam, lParam ) ;
		break ;
	default:
		return DefWindowProc( hWnd, msg, wParam, lParam ) ;
	}
	return 0 ;
}
