//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================//

#define PROTECTED_THINGS_DISABLE

#include <vgui/IPanel.h>
#include <vgui/IInput.h>
#include <vgui/ISurface.h>
#include <KeyValues.h>
#include <vgui/IVGui.h>

#include <vgui_controls/Controls.h>
#include <vgui_controls/MenuButton.h>
#include <vgui_controls/Menu.h>
#include <vgui_controls/TextImage.h>

// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>

using namespace vgui;

DECLARE_BUILD_FACTORY_DEFAULT_TEXT( MenuButton, MenuButton );

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
MenuButton::MenuButton(Panel *parent, const char *panelName, const char *text) : Button(parent, panelName, text)
{
	m_pMenu = NULL;
	m_iDirection = Menu::DOWN;
	m_pDropMenuImage = NULL;
	m_nImageIndex = -1;
	_openOffsetY = 0;

	SetDropMenuButtonStyle( false );
	SetUseCaptureMouse( false );
	SetButtonActivationType( ACTIVATE_ONPRESSED );
}

//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
MenuButton::~MenuButton() 
{
	delete m_pDropMenuImage;
}

//-----------------------------------------------------------------------------
// Purpose: attaches a menu to the menu button
//-----------------------------------------------------------------------------
void MenuButton::SetMenu(Menu *menu)
{
	m_pMenu = menu;

	if (menu)
	{
		m_pMenu->SetVisible(false);
		m_pMenu->AddActionSignalTarget(this);
		m_pMenu->SetParent(this);
	}
}

//-----------------------------------------------------------------------------
// Purpose: Never draw a focus border
//-----------------------------------------------------------------------------
void MenuButton::DrawFocusBorder(int tx0, int ty0, int tx1, int ty1)
{
}

//-----------------------------------------------------------------------------
// Purpose: Sets the direction from the menu button the menu should open
//-----------------------------------------------------------------------------
void MenuButton::SetOpenDirection(Menu::MenuDirection_e direction)
{
	m_iDirection = direction;
}


//-----------------------------------------------------------------------------
// Purpose: hides the menu
//-----------------------------------------------------------------------------
void MenuButton::HideMenu(void)
{
	if (!m_pMenu)
		return;

	// hide the menu
	m_pMenu->SetVisible(false);

	// unstick the button
	BaseClass::ForceDepressed(false);
	Repaint();

	OnHideMenu(m_pMenu);
}


//-----------------------------------------------------------------------------
// Purpose: Called when the menu button loses focus; hides the menu
//-----------------------------------------------------------------------------
void MenuButton::OnKillFocus( KeyValues *pParams )
{
	VPANEL hPanel = (VPANEL)pParams->GetPtr( "newPanel" );
	if ( m_pMenu && !m_pMenu->HasFocus() && hPanel != m_pMenu->GetVPanel() )
	{
		HideMenu();
	}
	BaseClass::OnKillFocus();
}

//-----------------------------------------------------------------------------
// Purpose: Called when the menu is closed
//-----------------------------------------------------------------------------
void MenuButton::OnMenuClose()
{
	HideMenu();
	PostActionSignal(new KeyValues("MenuClose"));
}

//-----------------------------------------------------------------------------
// Purpose: Sets the offset from where menu would normally be placed
//			Only is used if menu is ALIGN_WITH_PARENT
//-----------------------------------------------------------------------------
void MenuButton::SetOpenOffsetY(int yOffset)
{
	_openOffsetY = yOffset;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool MenuButton::CanBeDefaultButton(void)
{
    return false;
}

//-----------------------------------------------------------------------------
// Purpose: Handles hotkey accesses
//-----------------------------------------------------------------------------
void MenuButton::DoClick()
{
	if ( IsDropMenuButtonStyle() && 
		m_pDropMenuImage )
	{
		int mx, my;
		// force the menu to appear where the mouse button was pressed
		input()->GetCursorPos( mx, my );
		ScreenToLocal( mx, my );

		int contentW, contentH;
		m_pDropMenuImage->GetContentSize( contentW, contentH );
		int drawX = GetWide() - contentW - 2;
		if ( mx <= drawX || !OnCheckMenuItemCount() )
		{
			// Treat it like a "regular" button click
			BaseClass::DoClick();
			return;
		}
	}

	if ( !m_pMenu )
	{
		return;
	}

	// menu is already visible, hide the menu
	if (m_pMenu->IsVisible())
	{
		HideMenu();
		return;
	}

	// do nothing if menu is not enabled
	if (!m_pMenu->IsEnabled())
	{
		return;
	}
	// force the menu to compute required width/height
	m_pMenu->PerformLayout();

	// Now position it so it can fit in the workspace
	m_pMenu->PositionRelativeToPanel(this, m_iDirection, _openOffsetY );

	// make sure we're at the top of the draw order (and therefore our children as well)
	MoveToFront();

	// notify
	OnShowMenu(m_pMenu);

	// keep the button depressed
	BaseClass::ForceDepressed(true);

	// show the menu
	m_pMenu->SetVisible(true);

	// bring to focus
	m_pMenu->RequestFocus();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void MenuButton::OnKeyCodeTyped(KeyCode code)
{
	bool shift = (input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT));
	bool ctrl = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL));
	bool alt = (input()->IsKeyDown(KEY_LALT) || input()->IsKeyDown(KEY_RALT));

	if (!shift && !ctrl && !alt)
	{
		switch (code)
		{
		case KEY_ENTER:
			{
				if ( !IsDropMenuButtonStyle() )
				{
					DoClick();
				}
				break;
			}
		}
	}
	BaseClass::OnKeyCodeTyped(code);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void MenuButton::OnCursorEntered()
{
	Button::OnCursorEntered();
	// post a message to the parent menu.
	// forward the message on to the parent of this menu.
	KeyValues *msg = new KeyValues ("CursorEnteredMenuButton");
	// tell the parent this menuitem is the one that was entered so it can open the menu if it wants
	msg->SetInt("VPanel", GetVPanel());
	ivgui()->PostMessage(GetVParent(), msg, NULL);
}

// This style is like the IE "back" button where the left side acts like a regular button, the the right side has a little
//  combo box dropdown indicator and presents and submenu
void MenuButton::SetDropMenuButtonStyle( bool state )
{
	bool changed = m_bDropMenuButtonStyle != state;
	m_bDropMenuButtonStyle = state;
	if ( !changed )
		return;

	if ( state )
	{
		m_pDropMenuImage = new TextImage( "u" );
		IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
		m_pDropMenuImage->SetFont(pScheme->GetFont("Marlett", IsProportional()));
		// m_pDropMenuImage->SetContentAlignment(Label::a_west);
		// m_pDropMenuImage->SetTextInset(3, 0);
		m_nImageIndex = AddImage( m_pDropMenuImage, 0 );
	}
	else
	{
		ResetToSimpleTextImage();
		delete m_pDropMenuImage;
		m_pDropMenuImage = NULL;
		m_nImageIndex = -1;
	}
}

void MenuButton::ApplySchemeSettings( IScheme *pScheme )
{
	BaseClass::ApplySchemeSettings( pScheme );

	if ( m_pDropMenuImage )
	{
		SetImageAtIndex( 1, m_pDropMenuImage, 0 );
	}
}


void MenuButton::PerformLayout()
{
	BaseClass::PerformLayout();
	if ( !IsDropMenuButtonStyle() )
		return;

	Assert( m_nImageIndex >= 0 );
	if ( m_nImageIndex < 0 || !m_pDropMenuImage )
		return;

	int w, h;
	GetSize( w, h );

	int contentW, contentH;
	m_pDropMenuImage->ResizeImageToContent();
	m_pDropMenuImage->GetContentSize( contentW, contentH );

	SetImageBounds( m_nImageIndex, w - contentW - 2, contentW );
}

bool MenuButton::IsDropMenuButtonStyle() const
{
	return m_bDropMenuButtonStyle;
}

void MenuButton::Paint(void)
{
	BaseClass::Paint();

	if ( !IsDropMenuButtonStyle() )
		return;

	int contentW, contentH;
	m_pDropMenuImage->GetContentSize( contentW, contentH );
	m_pDropMenuImage->SetColor( IsEnabled() ? GetButtonFgColor() : GetDisabledFgColor1() );
	
	int drawX = GetWide() - contentW - 2;

	surface()->DrawSetColor(  IsEnabled() ? GetButtonFgColor() : GetDisabledFgColor1() );
	surface()->DrawFilledRect( drawX, 3, drawX + 1, GetTall() - 3 );
}

void MenuButton::OnCursorMoved( int x, int y )
{
	BaseClass::OnCursorMoved( x, y );

	if ( !IsDropMenuButtonStyle() )
		return;

	int contentW, contentH;
	m_pDropMenuImage->GetContentSize( contentW, contentH );
	int drawX = GetWide() - contentW - 2;
	if ( x <= drawX || !OnCheckMenuItemCount() )
	{
		SetButtonActivationType(ACTIVATE_ONPRESSEDANDRELEASED);
		SetUseCaptureMouse(true);
	}
	else
	{
		SetButtonActivationType(ACTIVATE_ONPRESSED);
		SetUseCaptureMouse(false);
	}
}

Menu *MenuButton::GetMenu()
{
	Assert( m_pMenu );
	return m_pMenu;
}