#include <windows.h>
#include "uiframe.h"
#include "ui.h"

// ----------------------------------------------------------------------------------
CUiFrame::CUiFrame(const char* name, CUiLayout* pParent, CUi* pUi)
	: CUiLayout(name, pParent, pUi)
{
	m_uiType			= eUiType_Frame;

	m_layers.clear();
	m_child.clear();
	
	m_pBackdrop			= NULL;
	m_id				= 0;
	m_frameLevel		= 0;	
	m_frameStrata		= eUIFrame_Strata_Background;
	m_clicksSet			= eMouse_Flag_LButton;
	m_dragSet			= eMouse_Flag_LButton;
	m_topLevel			= false;
	m_isEnable			= true;
	m_state.flag		= 0;
	m_sizingAnchorPoint = 0;

	m_backdropTileColor.SetColor( 0xFFFFFFFF );
	m_backdropEdgeColor.SetColor( 0xFFFFFFFF );

	m_pfRender			= NULL;

	if (pParent)
	{
		CUiFrame* pUiFrame = dynamic_cast<CUiFrame*>(pParent);
		if (pUiFrame)
			pUiFrame->InsertChild(this);
	}
}

// ----------------------------------------------------------------------------------
CUiFrame::~CUiFrame()
{	
	// 通知父元件移除自己
	if (m_pParent)
	{
		CUiFrame* pUiFrame = dynamic_cast<CUiFrame*>(m_pParent);
		if ( pUiFrame )
			pUiFrame->EraseChild(this);
		m_pParent = NULL;
	}

	// 刪除所有子元件
	for ( list<CUiFrame*>::iterator iter = m_child.begin(); iter != m_child.end(); iter++ )
	{
		(*iter)->m_pParent = NULL;
		delete (*iter);
	}
	m_child.clear();
	
	// 刪除所有資源物件
	for ( multimap<int, CUiLayout*>::iterator iter = m_layers.begin(); iter != m_layers.end(); iter++ )
		delete iter->second;
	m_layers.clear();
	
	// 刪除背景物件
	UI_SAFE_DELETE(m_pBackdrop);
	
	// 釋放所有事件資料
	// ClearEvent();	
}

// ----------------------------------------------------------------------------------
bool CUiFrame::HandleMsgProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	if (!m_isEnable || !m_isVisible || !m_state.isKeyboardEnable || m_pUi == NULL)
		return false;

	switch (uMsg)
	{
	case WM_CHAR:
		OnChar(wParam);

		switch ( wParam )
		{
		// Enter
		case L'\r':
			OnEnterPressed();
			break;
		// Tab
		case L'\t':
			OnTabPressed();
			break;
		// Space
		case L' ':
			OnSpacePressed();
			break;
		// Escape
		case 27:
			OnEscapePressed();
			break;
		}
		return true;

	case WM_KEYDOWN:
		OnPressed(wParam);

		switch( wParam )
		{
		case VK_UP:
			OnArrowUpPressed();
			break;

		case VK_DOWN:
			OnArrowDownPressed();
			break;
		}
		return true;
	}

	return false;
}

// ----------------------------------------------------------------------------------
bool CUiFrame::HandleMouse(CUiInput& input)
{
	CUiPoint pt((float)input.GetXPos(), (float)input.GetYPos());
	bool isMouseIn = ContainsPoint(pt);

	if (!m_isEnable || !m_isVisible || !m_state.isMouseEnable || m_pUi == NULL)
		return false;

	// 滑鼠軸向有做移動
	if ( input.GetXDelta() != 0 || input.GetYDelta() != 0 )
		OnMouseMove(pt);

	// 滾輪滾動
	if ( input.GetZDelta() != 0 )
		OnMouseWheel(pt, input.GetZDelta());

	// 按鈕狀態
	for (int key = 0; key < MAX_MOUSE_BUTTON_NUM; key++)
	{
		if (input.GetButtonDown(key))
		{
			if ( m_pUi->GetCapture() == NULL )
				m_pUi->SetCapture(this, key);

			// 記錄按下按鈕元件指標
			if ( isMouseIn )
			{
				m_pUi->SetMouseDown(key, this);
				OnMouseDown(pt, key);
			}
		}

		if (input.GetButtonUp(key))
		{
			// 如果目前為拖曳狀態
			if ( m_pUi->GetDragFrame() == this )
			{
				m_pUi->OnReceiveDrag(pt, this);
				m_pUi->SetDragFrame(NULL);
				OnDragStop();
			}

			// 當按下與放開在同一元件時觸發
			if ( m_pUi->GetMouseDown(key) == this )
			{
				if ( isMouseIn && (m_clicksSet & (0x01 << key)) )
					OnClick(pt, key);
			}

			// 解除鎖定狀態
			if ( m_pUi->GetCapture() && key == m_pUi->GetCaptureKey() )
				m_pUi->SetCapture(NULL, 0);

			// OnMouseUp(key);
		}
	}

	return true;
}

// ----------------------------------------------------------------------------------
bool CUiFrame::HandleKeyboard(CUiInput& input)
{	
	if (!m_isEnable || !m_isVisible || !m_state.isKeyboardEnable || m_pUi == NULL)
		return false;

	for (int i = 0; i < 256; i++)
	{
		if ( input.GetKeyDown(i) )
			OnKeyDown(i);

		if ( input.GetKeyUp(i) )
			OnKeyUp(i);
	}

	return true;
}

// ----------------------------------------------------------------------------------
void CUiFrame::Update(float elapsedTime)
{
	CUiPoint cursorOffset = m_pUi->GetCursorOffset();

	if (!m_isEnable || !m_isVisible)
		return;

	if ( m_state.isMoving )
		Moving( cursorOffset.m_x, cursorOffset.m_y );

	if ( m_state.isSizing )
		Sizing( m_sizingAnchorPoint, cursorOffset.m_x, cursorOffset.m_y );

	OnUpdate(elapsedTime);

	// 更新子元件
	for ( list<CUiFrame*>::iterator iter = m_child.begin(); iter != m_child.end(); iter++ )
		(*iter)->Update(elapsedTime);
}

// ----------------------------------------------------------------------------------
void CUiFrame::Render(float alpha)
{
	if ( !m_isVisible )
		return;	

	if ( m_pfRender )
		m_pfRender( this );

	alpha *= m_color.m_a;

	// 繪出背景
	if (m_pBackdrop)
	{
		CUiRectangle rc;		
		GetRectangle(&rc);

		CUiRGBA tileColor = m_backdropTileColor;
		CUiRGBA edgeColor = m_backdropEdgeColor;
		tileColor.SetAlphaScale(alpha);
		edgeColor.SetAlphaScale(alpha);

		CRuRectangle drawRect(rc.m_left, rc.m_top, rc.m_right, rc.m_bottom);
		m_pBackdrop->Draw(drawRect, tileColor.m_value , edgeColor.m_value);
	}

	// 繪出LAYERS物件
	for ( multimap<int, CUiLayout*>::iterator iter = m_layers.begin(); iter != m_layers.end(); iter++ )
		(iter->second)->Render(alpha);

	// 繪出自己
	OnPaint(alpha);

	// 繪出子元件
	for ( list<CUiFrame*>::iterator iter = m_child.begin(); iter != m_child.end(); iter++ )
		(*iter)->Render(alpha);
}

// ----------------------------------------------------------------------------------
void CUiFrame::Render3D(float alpha)
{
	if (!m_isVisible )
		return;

	alpha *= m_color.m_a;
	
	OnPaint3D(alpha);

	// 繪出子元件
	for ( list<CUiFrame*>::iterator iter = m_child.begin(); iter != m_child.end(); iter++ )
		(*iter)->Render3D(alpha);
}

// ----------------------------------------------------------------------------------
void CUiFrame::SetVisible(bool isVisible)
{
	if (m_isVisible != isVisible)
	{
		CUiLayout::SetVisible(isVisible);
		if ( m_isVisible )
			OnShow( GetLuaState() );
		else
			OnHide( GetLuaState() );
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::RegisterEvent(const char* event)
{
	if (m_pUi)
		m_pUi->RegisterEvent(event, this);
}

// ----------------------------------------------------------------------------------
void CUiFrame::UnregisterEvent(const char* event)
{
	if (m_pUi)
		m_pUi->UnregisterEvent(event, this);
}

// ----------------------------------------------------------------------------------
void CUiFrame::SetFrameStrata(UIFrameStrata strata)
{
	if ( m_frameStrata != strata )
	{
		m_frameStrata = strata;
		AdjustFrameLevel();
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::SetTopLevel(bool topLevel)
{
	if ( m_topLevel != topLevel )
	{
		m_topLevel = topLevel;
		AdjustFrameLevel();
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::SetFrameLevel(int level)
{
	if (m_frameLevel != level)
	{
		m_frameLevel = level;
		AdjustFrameLevel();
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::SetFocus()
{
	if (m_pUi)
		m_pUi->LockKeyboard(this);
}

// ----------------------------------------------------------------------------------
void CUiFrame::ClearFocus()
{
	if (m_pUi)
		m_pUi->LockKeyboard(NULL);
}

// ----------------------------------------------------------------------------------
void CUiFrame::SetBackdrop(CTextureBackdrop* pBackdrop)
{
	UI_SAFE_DELETE(m_pBackdrop);
	if (pBackdrop)
	{
		m_pBackdrop = new CTextureBackdrop;
		*m_pBackdrop = *pBackdrop;
	}
}

// ----------------------------------------------------------------------------------
bool CUiFrame::IsParentEnable()
{
	CUiFrame* pParent = dynamic_cast<CUiFrame*>(m_pParent);
	while (pParent)
	{
		if (!pParent->m_isEnable || !pParent->m_isVisible)
			return false;
		pParent = dynamic_cast<CUiFrame*>(pParent->m_pParent);
	}
	return (m_isEnable && m_isVisible);
}

// ----------------------------------------------------------------------------------
void CUiFrame::StartMoving()
{
	m_state.isMoving = true;
}

// ----------------------------------------------------------------------------------
void CUiFrame::StartSizing(int anchorPoint)
{
	m_state.isSizing = true;
	m_sizingAnchorPoint = anchorPoint;
}

// ----------------------------------------------------------------------------------
void CUiFrame::StopMovingOrSizing()
{
	m_state.isMoving = false;
	m_state.isSizing = false;
}

// ----------------------------------------------------------------------------------
bool CUiFrame::ContainsPoint(CUiPoint pt)
{
	CUiRectangle rect;
	GetRectangle(&rect);
	if ( pt.m_x < rect.m_left + m_hitRectInsets.m_left )
		return false;
	else if ( pt.m_y < rect.m_top + m_hitRectInsets.m_top )
		return false;
	else if ( pt.m_x > rect.m_right - m_hitRectInsets.m_right )
		return false;
	else if ( pt.m_y > rect.m_bottom - m_hitRectInsets.m_bottom )
		return false;

	return true;
}

// ----------------------------------------------------------------------------------
CUiFrame* CUiFrame::GetFrameAtPoint(CUiPoint pt, CUiFrame* pExclude)
{
	if (m_isVisible && m_isEnable)
	{
		for (list<CUiFrame*>::reverse_iterator iter = m_child.rbegin(); iter != m_child.rend(); iter++ )
		{
			CUiFrame *pFocus;
			if ( (pFocus = (*iter)->GetFrameAtPoint(pt , pExclude)) != NULL )
				return pFocus;
		}

		if ( m_state.isMouseEnable && this != pExclude && ContainsPoint(pt) )
			return this;
	}
	return NULL;
	
	/*
	if (m_isVisible && m_isEnable)
	{
		if ( ContainsPoint(pt) )
		{
			for (list<CUiFrame*>::reverse_iterator iter = m_child.rbegin(); iter != m_child.rend(); iter++ )
			{
				CUiFrame *pFocus;
				if ( (pFocus = (*iter)->GetFrameAtPoint(pt , pExclude)) != NULL )
					return pFocus;
			}

			if ( m_state.isMouseEnable && this != pExclude )
				return this;
		}
	}	
	return NULL;
	*/
}

// ----------------------------------------------------------------------------------
CUiFrame* CUiFrame::GetFrameAtKeyboard(CUiFrame* pExclude)
{
	if (m_isVisible && m_isEnable)
	{
		for (list<CUiFrame*>::reverse_iterator iter = m_child.rbegin(); iter != m_child.rend(); iter++)
		{
			CUiFrame* pFocus;
			if ( (pFocus = (*iter)->GetFrameAtKeyboard(pExclude)) != NULL )
				return pFocus;
		}

		if (m_state.isKeyboardEnable && m_uiType != eUiType_EditBox && this != pExclude)
			return this;
	}
	return NULL;
}

// ----------------------------------------------------------------------------------
void CUiFrame::SetScripts(int type, const char* script, lua_CFunction func)
{
	lua_State* L = GetLuaState();
	if (L == NULL)
		return;	

	// first push this table
	CUiLuaLayout::PushLayoutTable(L, this);
	if (!lua_isnil(L, -1))
	{			
		const char* func_narg = NULL;
		const char* table_key = NULL;
		switch(type)
		{
		case eEventType_Load:
			func_narg = "this";
			table_key = UI_LUA_ONLOAD;
			break;

		case eEventType_Update:
			func_narg = "this, elapsedTime";
			table_key = UI_LUA_ONUPDATE;
			break;

		case eEventType_Resize:
			func_narg = "this";
			table_key = UI_LUA_ONRESIZE;
			break;

		case eEventType_Show:
			func_narg = "this";
			table_key = UI_LUA_ONSHOW;
			break;

		case eEventType_Hide:
			func_narg = "this";
			table_key = UI_LUA_ONHIDE;
			break;

		case eEventType_TabPressed:
			func_narg = "this";
			table_key = UI_LUA_ONTABPRESSED;
			break;

		case eEventType_EnterPressed:
			func_narg = "this";
			table_key = UI_LUA_ONENTERPRESSED;
			break;

		case eEventType_EscapePressed:
			func_narg = "this";
			table_key = UI_LUA_ONESCAPEPRESSED;
			break;

		case eEventType_SpacePressed:
			func_narg = "this";
			table_key = UI_LUA_ONSPACEPRESSED;
			break;

		case eEventType_ArrowUpPressed:
			func_narg = "this";
			table_key = UI_LUA_ONARROWUPPRESSED;
			break;

		case eEventType_ArrowDownPressed:
			func_narg = "this";
			table_key = UI_LUA_ONARROWDOWNPRESSED;
			break;

		case eEventType_KeyDown:
			func_narg = "this, key";
			table_key = UI_LUA_ONKEYDOWN;
			break;

		case eEventType_KeyUp:
			func_narg = "this, key";
			table_key = UI_LUA_ONKEYUP;
			break;

		case eEventType_Char:
			func_narg = "this, char";
			table_key = UI_LUA_ONCHAR;
			break;

		case eEventType_MouseDown:
			func_narg = "this, key";
			table_key = UI_LUA_ONMOUSEDOWN;
			break;

		case eEventType_MouseUp:
			func_narg = "this, key";
			table_key = UI_LUA_ONMOUSEUP;
			break;

		case eEventType_MouseWheel:
			func_narg = "this, delta";
			table_key = UI_LUA_ONMOUSEWHEEL;
			break;

		case eEventType_MouseEnter:
			func_narg = "this";
			table_key = UI_LUA_ONMOUSEENTER;
			break;

		case eEventType_MouseLeave:
			func_narg = "this";
			table_key = UI_LUA_ONMOUSELEAVE;
			break;

		case eEventType_Click:
			func_narg = "this, key";
			table_key = UI_LUA_ONCLICK;
			break;

		case eEventType_DoubleClick:
			func_narg = "this, key";
			table_key = UI_LUA_ONDOUBLECLICK;
			break;

		case eEventType_DragBegin:
			func_narg = "this";
			table_key = UI_LUA_ONDRAGBEGIN;
			break;

		case eEventType_DragStop:
			func_narg = "this";
			table_key = UI_LUA_ONDRAGSTOP;
			break;

		case eEventType_ReceiveDrag:
			func_narg = "this";
			table_key = UI_LUA_ONRECEIVEDRAG;
			break;

		case eEventType_ValueChanged:
			func_narg = "this, arg1";
			table_key = UI_LUA_ONVALUECHANGED;
			break;

		case eEventType_TextChanged:
			func_narg = "this";
			table_key = UI_LUA_ONTEXTCHANGED;
			break;

		case eEventType_ScrollRangeChanged:
			func_narg = "this, arg1, arg2";
			table_key = UI_LUA_ONSCROLLRANGECHANGED;
			break;

		case eEventType_VerticalScroll:
			func_narg = "this, arg1";
			table_key = UI_LUA_ONVERTICALSCROLL;
			break;

		case eEventType_HorizontalScroll:
			func_narg = "this, arg1";
			table_key = UI_LUA_ONHORIZONTALSCROLL;
			break;

		case eEventType_Event:
			func_narg = "this, event";
			table_key = UI_LUA_ONEVENT;
			break;
		}

		if (script)
		{
			if (func_narg && table_key)
			{
				char* tmp = new char[strlen(script) + 127];
				sprintf(tmp, "function %s (%s)\n%s\nend", table_key, func_narg, script);
				if (luaL_loadbuffer(L, tmp, strlen(tmp), 0) != 0 || lua_resume(L, 0) != 0 )
				{
					const char* err = lua_tostring(L, -1);
					lua_pop(L, 1);
					UiOuputError(err);
				}
				else
				{
					lua_getglobal(L, table_key);
					if (!lua_isnil(L, -1))
					{
						lua_pushstring(L, table_key);
						lua_insert(L, -2);
						lua_rawset(L, -3);
						lua_pushnil(L);
						lua_setglobal(L, table_key);
					}
					else
						lua_pop(L, 1);
				}
				delete [] tmp;
			}
		}
		else if (func)
		{
			lua_pushstring(L, table_key);
			lua_pushcfunction(L, func);
			lua_rawset(L, -3);
		}
	}
	lua_pop(L, 1);
}

// ----------------------------------------------------------------------------------
void CUiFrame::SetLayers(int layer, CUiLayout* pUiLayout)
{
	if (pUiLayout)
		m_layers.insert(make_pair(layer, pUiLayout));
}

// ----------------------------------------------------------------------------------
CUiFrame* CUiFrame::GetMouseDown(int key)
{
	return m_pUi->GetMouseDown(key);
}

// ----------------------------------------------------------------------------------
void CUiFrame::GetBottomRight(float& x, float& y)
{
	if (m_isVisible)
	{
		CUiLayout::GetBottomRight(x, y);

		// LAYERS物件
		for ( multimap<int, CUiLayout*>::iterator iter = m_layers.begin(); iter != m_layers.end(); iter++ )
			(iter->second)->GetBottomRight(x ,y);

		// 子元件
		for ( list<CUiFrame*>::iterator iter = m_child.begin(); iter != m_child.end(); iter++ )
			(*iter)->GetBottomRight(x ,y);
	}
}

// ----------------------------------------------------------------------------------
inline const char* CUiFrame::GetButtonName(BYTE num)
{
	switch (num)
	{
	case MOUSE_LBUTTON:
		return UI_LUA_LBUTTON;

	case MOUSE_RBUTTON:
		return UI_LUA_RBUTTON;

	case MOUSE_MBUTTON:
		return UI_LUA_MBUTTON;

	case MOUSE_XBUTTON:
		return UI_LUA_XBUTTON;
	}
	return NULL;
}

// ----------------------------------------------------------------------------------
inline const char* CUiFrame::GetKeyName(BYTE num)
{
	switch (num)
	{
	case KEY_ESCAPE:
		return UI_LUA_KEY_ESC;

	case KEY_MINUS:
		return UI_LUA_KEY_MINUS;

	case KEY_EQUALS:
		return UI_LUA_KEY_EQUALS;

	case KEY_BACKSPACE:
		return UI_LUA_KEY_BACKSPACE;

	case KEY_TAB:
		return UI_LUA_KEY_TAB;

	case KEY_LBRACKET:
		return UI_LUA_KEY_LBRACKET;

	case KEY_RBRACKET:
		return UI_LUA_KEY_RBRACKET;

	case KEY_ENTER:
		return UI_LUA_KEY_ENTER;

	case KEY_LCTRL:
	case KEY_RCTRL:
		return UI_LUA_KEY_CTRL;

	case KEY_LSHIFT:
	case KEY_RSHIFT:
		return UI_LUA_KEY_SHIFT;

	case KEY_LALT:
	case KEY_RALT:
		return UI_LUA_KEY_ALT;

	case KEY_0:
		return UI_LUA_KEY_0;
	case KEY_1:
		return UI_LUA_KEY_1;
	case KEY_2:
		return UI_LUA_KEY_2;
	case KEY_3:
		return UI_LUA_KEY_3;
	case KEY_4:
		return UI_LUA_KEY_4;
	case KEY_5:
		return UI_LUA_KEY_5;
	case KEY_6:
		return UI_LUA_KEY_6;
	case KEY_7:
		return UI_LUA_KEY_7;
	case KEY_8:
		return UI_LUA_KEY_8;
	case KEY_9:
		return UI_LUA_KEY_9;

	case KEY_A:
		return UI_LUA_KEY_A;
	case KEY_B:
		return UI_LUA_KEY_B;
	case KEY_C:
		return UI_LUA_KEY_C;
	case KEY_D:
		return UI_LUA_KEY_D;
	case KEY_E:
		return UI_LUA_KEY_E;
	case KEY_F:
		return UI_LUA_KEY_F;
	case KEY_G:
		return UI_LUA_KEY_G;
	case KEY_H:
		return UI_LUA_KEY_H;
	case KEY_I:
		return UI_LUA_KEY_I;
	case KEY_J:
		return UI_LUA_KEY_J;
	case KEY_K:
		return UI_LUA_KEY_K;
	case KEY_L:
		return UI_LUA_KEY_L;
	case KEY_M:
		return UI_LUA_KEY_M;
	case KEY_N:
		return UI_LUA_KEY_N;
	case KEY_O:
		return UI_LUA_KEY_O;
	case KEY_P:
		return UI_LUA_KEY_P;
	case KEY_Q:
		return UI_LUA_KEY_Q;
	case KEY_R:
		return UI_LUA_KEY_R;
	case KEY_S:
		return UI_LUA_KEY_S;
	case KEY_T:
		return UI_LUA_KEY_T;
	case KEY_U:
		return UI_LUA_KEY_U;
	case KEY_V:
		return UI_LUA_KEY_V;
	case KEY_W:
		return UI_LUA_KEY_W;
	case KEY_X:
		return UI_LUA_KEY_X;
	case KEY_Y:
		return UI_LUA_KEY_Y;
	case KEY_Z:
		return UI_LUA_KEY_Z;

	case KEY_SEMICOLON:
		return UI_LUA_KEY_SEMICOLON;

	case KEY_APOSTROPHE:
		return UI_LUA_KEY_APOSTROPHE;

	case KEY_GRAVE:
		return UI_LUA_KEY_GRAVE;

	case KEY_BACKSLASH:
		return UI_LUA_KEY_BACKSLASH;

	case KEY_COMMA:
		return UI_LUA_KEY_COMMA;

	case KEY_PERIOD:
		return UI_LUA_KEY_PERIOD;

	case KEY_SLASH:
		return UI_LUA_KEY_SLASH;

	case KEY_SPACE:
		return UI_LUA_KEY_SPACE;

	case KEY_CAPSLOCK:
		return UI_LUA_KEY_CAPSLOCK;

	case KEY_F1:
		return UI_LUA_KEY_F1;
	case KEY_F2:
		return UI_LUA_KEY_F2;
	case KEY_F3:
		return UI_LUA_KEY_F3;
	case KEY_F4:
		return UI_LUA_KEY_F4;
	case KEY_F5:
		return UI_LUA_KEY_F5;
	case KEY_F6:
		return UI_LUA_KEY_F6;
	case KEY_F7:
		return UI_LUA_KEY_F7;
	case KEY_F8:
		return UI_LUA_KEY_F8;
	case KEY_F9:
		return UI_LUA_KEY_F9;
	case KEY_F10:
		return UI_LUA_KEY_F10;
	case KEY_F11:
		return UI_LUA_KEY_F11;
	case KEY_F12:
		return UI_LUA_KEY_F12;

	case KEY_SYSRQ:
		return UI_LUA_KEY_SYSRQ;
	case KEY_SCROLLLOCK:
		return UI_LUA_KEY_SCROLLLOCK;
	case KEY_PAUSE:
		return UI_LUA_KEY_PAUSE;

	case KEY_NUMLOCK:
		return UI_LUA_KEY_NUMLOCK;
	case KEY_NUMPAD0:
		return UI_LUA_KEY_NUMPAD0;
	case KEY_NUMPAD1:
		return UI_LUA_KEY_NUMPAD1;
	case KEY_NUMPAD2:
		return UI_LUA_KEY_NUMPAD2;
	case KEY_NUMPAD3:
		return UI_LUA_KEY_NUMPAD3;
	case KEY_NUMPAD4:
		return UI_LUA_KEY_NUMPAD4;
	case KEY_NUMPAD5:
		return UI_LUA_KEY_NUMPAD5;
	case KEY_NUMPAD6:
		return UI_LUA_KEY_NUMPAD6;
	case KEY_NUMPAD7:
		return UI_LUA_KEY_NUMPAD7;
	case KEY_NUMPAD8:
		return UI_LUA_KEY_NUMPAD8;
	case KEY_NUMPAD9:
		return UI_LUA_KEY_NUMPAD9;
	case KEY_ADD:
		return UI_LUA_KEY_ADD;
	case KEY_SUBTRACT:
		return UI_LUA_KEY_SUBTRACT;
	case KEY_DIVIDE:
		return UI_LUA_KEY_DIVIDE;
	case KEY_MULTIPLY:
		return UI_LUA_KEY_MULTIPLY;
	case KEY_DECIMAL:
		return UI_LUA_KEY_DECIMAL;
	case KEY_NUMPADENTER:
		return UI_LUA_KEY_NUMPADENTER;

	case KEY_INSERT:
		return UI_LUA_KEY_INSERT;
	case KEY_DELETE:
		return UI_LUA_KEY_DELETE;
	case KEY_HOME:
		return UI_LUA_KEY_HOME;
	case KEY_END:
		return UI_LUA_KEY_END;
	case KEY_PAGEUP:
		return UI_LUA_KEY_PAGEUP;
	case KEY_PAGEDOWN:
		return UI_LUA_KEY_PAGEDOWN;

	case KEY_UP:
		return UI_LUA_KEY_UP;
	case KEY_DOWN:
		return UI_LUA_KEY_DOWN;
	case KEY_LEFT:
		return UI_LUA_KEY_LEFT;
	case KEY_RIGHT:
		return UI_LUA_KEY_RIGHT;

	case KEY_LWIN:
	case KEY_RWIN:
		return UI_LUA_KEY_WIN;
	case KEY_APPS:
		return UI_LUA_KEY_APPS;
	}
	return NULL;
}

// ----------------------------------------------------------------------------------
void CUiFrame::CallLuaFunc(lua_State* L, const char* type_key, int narg)
{
	assert(L);

	int pop_count = narg + 1;
	CUiLuaLayout::PushLayoutTable(L, this);
	if (!lua_isnil(L, -1))
	{
		pop_count++;
		lua_pushstring(L, type_key);
		lua_rawget(L, -2);
		if (!lua_isnil(L, -1))
		{
			lua_insert(L, -(2 + narg));					// move function
			lua_insert(L, -(1 + narg));					// move table
			if (lua_pcall(L, 1+narg, 0, 0) != 0)
			{				
				const char* err = lua_tostring(L, -1);
				lua_pop(L, 1);
				UiOuputError(err);
			}
			pop_count -= 2 + narg;
		}
	}
	lua_pop(L, pop_count);
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnLoad()
{
	lua_State* L = GetLuaState();
	if ( L )
	{
		CallLuaFunc(L, UI_LUA_ONLOAD, 0);
	}	
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnResize()
{	
	lua_State* L = GetLuaState();
	if (L)
	{
		CallLuaFunc(L, UI_LUA_ONRESIZE, 0);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnShow(lua_State* L)
{
	for (list<CUiFrame*>::reverse_iterator iter = m_child.rbegin(); iter != m_child.rend(); iter++ )
	{
		if ( (*iter)->m_isVisible )
			(*iter)->OnShow(L);
	}

	CallLuaFunc(L, UI_LUA_ONSHOW, 0);
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnHide(lua_State* L)
{	
	/*
	for (list<CUiFrame*>::reverse_iterator iter = m_child.rbegin(); iter != m_child.rend(); iter++ )
		(*iter)->OnHide(L);
	*/

	CallLuaFunc(L, UI_LUA_ONHIDE, 0);
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnUpdate(float elapsedTime)
{
	lua_State* L = GetLuaState();
	if (L)
	{
		lua_pushnumber(L, elapsedTime);
		CallLuaFunc(L, UI_LUA_ONUPDATE, 1);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnMouseLeave(CUiPoint pt)
{
	lua_State* L = GetLuaState();
	if (L)
	{
		CallLuaFunc(L, UI_LUA_ONMOUSELEAVE, 0);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnMouseEnter(CUiPoint pt)
{
	lua_State* L = GetLuaState();
	if (L)
	{
		CallLuaFunc(L, UI_LUA_ONMOUSEENTER, 0);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnMouseMove(CUiPoint pt)
{
	/*
	if ( m_isMovable && m_pUi->GetDragFrame() == this )
	{
		CUiPoint pt = GetPos();
		pt.m_x += input->GetXPos() - input->GetXOldPos();
		pt.m_y += input->GetYPos() - input->GetYOldPos();
		SetPos(pt);
	}
	*/

	// 若沒有元件在拖曳狀態,檢查元件自己是否可以觸發拖曳事件
	if ( m_pUi->GetDragFrame() == NULL && m_pUi->GetCapture() == this)
	{
		int key = m_pUi->GetCaptureKey();		
		if ( m_dragSet & (0x01 << key) && m_pUi->GetMouseDown(key) )
		{
			m_pUi->SetDragFrame( this );
			OnDragBegin();
		}
	}	
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnMouseWheel(CUiPoint pt, int delta)
{
	lua_State* L = GetLuaState();
	if (L)
	{
		lua_pushnumber(L, delta);
		CallLuaFunc(L, UI_LUA_ONMOUSEWHEEL, 1);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnClick(CUiPoint pt, int key)
{
	lua_State* L = GetLuaState();
	if (L)
	{
		lua_pushstring(L, GetButtonName(key));
		CallLuaFunc(L, UI_LUA_ONCLICK, 1);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnDoubleClick(CUiPoint pt, int key)
{
	lua_State* L = GetLuaState();
	if (L)
	{
		lua_pushstring(L, GetButtonName(key));
		CallLuaFunc(L, UI_LUA_ONDOUBLECLICK, 1);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnMouseDown(CUiPoint pt, int key)
{
	lua_State* L = GetLuaState();
	if (L)
	{
		lua_pushstring(L, GetButtonName(key));
		CallLuaFunc(L, UI_LUA_ONMOUSEDOWN, 1);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnMouseUp(CUiPoint pt, int key)
{
	lua_State* L = GetLuaState();
	if (L)
	{
		lua_pushstring(L, GetButtonName(key));
		CallLuaFunc(L, UI_LUA_ONMOUSEUP, 1);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnDragBegin()
{
	lua_State* L = GetLuaState();
	if (L)
	{		
		CallLuaFunc(L, UI_LUA_ONDRAGBEGIN, 0);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnDragStop()
{
	lua_State* L = GetLuaState();
	if (L)
	{		
		CallLuaFunc(L, UI_LUA_ONDRAGSTOP, 0);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnReceiveDrag()
{
	lua_State* L = GetLuaState();
	if (L)
	{		
		CallLuaFunc(L, UI_LUA_ONRECEIVEDRAG, 0);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnChar(WPARAM wParam)
{
	lua_State* L = GetLuaState();
	if (L)
	{		
		lua_pushnumber(L, wParam);
		CallLuaFunc(L, UI_LUA_ONCHAR, 1);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnPressed(WPARAM wParam)
{	
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnKeyDown(int key)
{
	lua_State* L = GetLuaState();
	if (L)
	{		
		lua_pushstring(L, GetKeyName(key));
		CallLuaFunc(L, UI_LUA_ONKEYDOWN, 1);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnKeyUp(int key)
{
	lua_State* L = GetLuaState();
	if (L)
	{		
		lua_pushstring(L, GetKeyName(key));
		CallLuaFunc(L, UI_LUA_ONKEYUP, 0);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnEnterPressed()
{
	lua_State* L = GetLuaState();
	if (L)
	{
		CallLuaFunc(L, UI_LUA_ONENTERPRESSED, 0);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnTabPressed()
{
	lua_State* L = GetLuaState();
	if (L)
	{		
		CallLuaFunc(L, UI_LUA_ONTABPRESSED, 0);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnSpacePressed()
{
	lua_State* L = GetLuaState();
	if (L)
	{		
		CallLuaFunc(L, UI_LUA_ONSPACEPRESSED, 0);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnEscapePressed()
{
	lua_State* L = GetLuaState();
	if (L)
	{		
		CallLuaFunc(L, UI_LUA_ONESCAPEPRESSED, 0);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnArrowUpPressed()
{
	lua_State* L = GetLuaState();
	if (L)
	{		
		CallLuaFunc(L, UI_LUA_ONARROWUPPRESSED, 0);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnArrowDownPressed()
{
	lua_State* L = GetLuaState();
	if (L)
	{		
		CallLuaFunc(L, UI_LUA_ONARROWDOWNPRESSED, 0);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnTextChanged()
{
	lua_State* L = GetLuaState();
	if (L)
	{
		CallLuaFunc(L, UI_LUA_ONTEXTCHANGED, 0);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnValueChanged(float arg1)
{
	lua_State* L = GetLuaState();
	if (L)
	{
		lua_pushnumber(L, arg1);
		CallLuaFunc(L, UI_LUA_ONVALUECHANGED, 1);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnVerticalScroll(float arg1)
{
	lua_State* L = GetLuaState();
	if (L)
	{
		lua_pushnumber(L, arg1);
		CallLuaFunc(L, UI_LUA_ONVERTICALSCROLL, 1);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnHorizontalScroll(float arg1)
{
	lua_State* L = GetLuaState();
	if (L)
	{
		lua_pushnumber(L, arg1);
		CallLuaFunc(L, UI_LUA_ONHORIZONTALSCROLL, 1);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnScrollRangeChanged(float arg1, float arg2)
{
	lua_State* L = GetLuaState();
	if (L)
	{
		lua_pushnumber(L, arg1);
		lua_pushnumber(L, arg2);
		CallLuaFunc(L, UI_LUA_ONSCROLLRANGECHANGED, 2);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::OnEvent(const char* event)
{
	lua_State* L = GetLuaState();
	if (L)
	{
        lua_pushstring(L, event);
		CallLuaFunc(L, UI_LUA_ONEVENT, 1);
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::EraseChild(CUiFrame *pUiFrame)
{
	assert( pUiFrame );
	for ( list<CUiFrame*>::iterator iter = m_child.begin(); iter != m_child.end(); iter++ )
	{
		if ( (*iter) == pUiFrame )
		{
			m_child.erase( iter );
			break;
		}
	}
}

// ----------------------------------------------------------------------------------
void CUiFrame::InsertChild(CUiFrame *pUiFrame)
{
	assert( pUiFrame );

	bool isInsert = false;

	// 找尋適當插入點
	for ( list<CUiFrame*>::iterator iter = m_child.begin(); iter != m_child.end(); iter++ )
	{
		CUiFrame* frame = *iter;
		if ( frame->m_frameStrata < pUiFrame->m_frameStrata )
			continue;

		if ( frame->m_frameStrata > pUiFrame->m_frameStrata || frame->m_topLevel || frame->m_frameLevel > pUiFrame->m_frameLevel )
		{
			m_child.insert(iter, pUiFrame);
			isInsert = true;
			break;
		}
	}

	if ( !isInsert )
		m_child.push_back(pUiFrame);
}

// ----------------------------------------------------------------------------------
void CUiFrame::AdjustFrameLevel()
{
	if ( m_pParent )
	{
		CUiFrame* pParent = dynamic_cast<CUiFrame*>(m_pParent);
		if (pParent)
		{
			pParent->EraseChild(this);
			pParent->InsertChild(this);
			pParent->AdjustFrameLevel();
		}
	}
}