//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================//


#include <stdio.h>
#include <assert.h>
#include <utlvector.h>
#include <vstdlib/IKeyValuesSystem.h>
#include <ctype.h>	// isdigit()

#include <materialsystem/imaterial.h>

#include <vgui/IBorder.h>
#include <vgui/IInput.h>
#include <vgui/IPanel.h>
#include <vgui/IScheme.h>
#include <vgui/ISurface.h>
#include <vgui/ISystem.h>
#include <vgui/ILocalize.h>
#include <vgui/IVGui.h>
#include <KeyValues.h>
#include <vgui/MouseCode.h>

#include <vgui_controls/Panel.h>
#include <vgui_controls/BuildGroup.h>
#include <vgui_controls/Tooltip.h>
#include <vgui_controls/PHandle.h>
#include <vgui_controls/Controls.h>
#include "vgui_controls/Menu.h"
#include "vgui_controls/MenuItem.h"

#include "UtlSortVector.h"

#include "tier1/utldict.h"
#include "tier1/utlbuffer.h"
#include "mempool.h"
#include "filesystem.h"
#include "tier0/icommandline.h"
#include "tier0/minidump.h"

#include "tier0/vprof.h"

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

using namespace vgui;

#define TRIPLE_PRESS_MSEC	300

const char *g_PinCornerStrings [] =
{
	"PIN_TOPLEFT",
	"PIN_TOPRIGHT",
	"PIN_BOTTOMLEFT",
	"PIN_BOTTOMRIGHT",

	"PIN_CENTER_TOP",
	"PIN_CENTER_RIGHT",
	"PIN_CENTER_BOTTOM",
	"PIN_CENTER_LEFT",
};

COMPILE_TIME_ASSERT( Panel::PIN_LAST == ARRAYSIZE( g_PinCornerStrings ) );

extern int GetBuildModeDialogCount();

static char *CopyString( const char *in )
{
	if ( !in )
		return NULL;

	int len = strlen( in );
	char *n = new char[ len + 1 ];
	Q_strncpy( n, in, len  + 1 );
	return n;
}

#ifdef STAGING_ONLY
ConVar tf_strict_mouse_up_events( "tf_strict_mouse_up_events", "0", FCVAR_ARCHIVE, "Only allow Mouse-Release events to happens on panels we also Mouse-Downed in" );
#endif

// Temporary convar to help debug why the MvMVictoryMannUpPanel TabContainer is sometimes way off to the left.
ConVar tf_debug_tabcontainer( "tf_debug_tabcontainer", "0", FCVAR_HIDDEN, "Spew TabContainer dimensions." );

#if defined( VGUI_USEDRAGDROP )
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
struct vgui::DragDrop_t
{
	DragDrop_t() :
		m_bDragEnabled( false ),
		m_bShowDragHelper( true ),
		m_bDropEnabled( false ),
		m_bDragStarted( false ),
		m_nDragStartTolerance( 8 ),
		m_bDragging( false ),
		m_lDropHoverTime( 0 ),
		m_bDropMenuShown( false ),
		m_bPreventChaining( false )
	{
		m_nStartPos[ 0 ] = m_nStartPos[ 1 ] = 0;
		m_nLastPos[ 0 ] = m_nLastPos[ 1 ] = 0;
	}

	// Drag related data
	bool		m_bDragEnabled;
	bool		m_bShowDragHelper;
	bool		m_bDragging;
	bool		m_bDragStarted;
	// How many pixels the dragged box must move before showing the outline rect...
	int			m_nDragStartTolerance;
	int			m_nStartPos[ 2 ];
	int			m_nLastPos[ 2 ];
	CUtlVector< KeyValues * >	m_DragData;
	CUtlVector< PHandle >		m_DragPanels;

	// Drop related data
	bool		m_bDropEnabled;
	// A droppable panel can have a hover context menu, which will show up after m_flHoverContextTime of hovering
	float		m_flHoverContextTime;

	PHandle			m_hCurrentDrop;
	// Amount of time hovering over current drop target
	long			m_lDropHoverTime;
	bool			m_bDropMenuShown;
	DHANDLE< Menu >	m_hDropContextMenu;

	// Misc data
	bool			m_bPreventChaining;
};

//-----------------------------------------------------------------------------
// Purpose: Helper for painting to the full screen...
//-----------------------------------------------------------------------------
class CDragDropHelperPanel : public Panel
{
	DECLARE_CLASS_SIMPLE( CDragDropHelperPanel, Panel );
public:
	CDragDropHelperPanel();

	virtual VPANEL IsWithinTraverse(int x, int y, bool traversePopups);
	virtual void PostChildPaint();

	void AddPanel( Panel *current );

	void RemovePanel( Panel *search );

private:
	struct DragHelperPanel_t
	{
		PHandle		m_hPanel;
	};

	CUtlVector< DragHelperPanel_t >	m_PaintList;
};

vgui::DHANDLE< CDragDropHelperPanel >	s_DragDropHelper;
#endif

#if defined( VGUI_USEKEYBINDINGMAPS )

BoundKey_t::BoundKey_t():
	isbuiltin( true ),
	bindingname( 0 ),
	keycode( KEY_NONE ),
	modifiers( 0 )
{
}

BoundKey_t::BoundKey_t( const BoundKey_t& src )
{
	isbuiltin			= src.isbuiltin;
	bindingname			= isbuiltin ? src.bindingname : CopyString( src.bindingname );
	keycode				= src.keycode;
	modifiers			= src.modifiers;
}

BoundKey_t& BoundKey_t::operator =( const BoundKey_t& src )
{
	if ( this == &src )
		return *this;
	isbuiltin			= src.isbuiltin;
	bindingname			= isbuiltin ? src.bindingname : CopyString( src.bindingname );
	keycode				= src.keycode;
	modifiers			= src.modifiers;
	return *this;
}


BoundKey_t::~BoundKey_t()
{
	if ( !isbuiltin )
	{
		delete[] bindingname;
	}
}

KeyBindingMap_t::KeyBindingMap_t() :
	bindingname( 0 ),
	func( 0 ),
	helpstring( 0 ),
	docstring( 0 ),
	passive( false )
{
}

KeyBindingMap_t::KeyBindingMap_t( const KeyBindingMap_t& src )
{
	bindingname			= src.bindingname;
	helpstring			= src.helpstring;
	docstring			= src.docstring;

	func				= src.func;
	passive				= src.passive;
}

KeyBindingMap_t::~KeyBindingMap_t()
{
}

class CKeyBindingsMgr
{
public:
	CKeyBindingsMgr() :
		m_Bindings( 0, 0, KeyBindingContextHandleLessFunc ),
		m_nKeyBindingContexts( 0 )
	{
	}

	struct KBContext_t
	{
		KBContext_t() :
			m_KeyBindingsFile( UTL_INVAL_SYMBOL ),
			m_KeyBindingsPathID( UTL_INVAL_SYMBOL )
		{
			m_Handle = INVALID_KEYBINDINGCONTEXT_HANDLE;
		}

		KBContext_t( const KBContext_t& src )
		{
			m_Handle = src.m_Handle;
			m_KeyBindingsFile = src.m_KeyBindingsFile;
			m_KeyBindingsPathID = src.m_KeyBindingsPathID;
			int c = src.m_Panels.Count();
			for ( int i = 0; i < c; ++i )
			{
				m_Panels.AddToTail( src.m_Panels[ i ] );
			}
		}

		KeyBindingContextHandle_t	m_Handle;
		CUtlSymbol					m_KeyBindingsFile;
		CUtlSymbol					m_KeyBindingsPathID;
		CUtlVector< Panel * >		m_Panels;
	};

	static bool KeyBindingContextHandleLessFunc( const KBContext_t& lhs, const KBContext_t& rhs )
	{
		return lhs.m_Handle < rhs.m_Handle;
	}

	KeyBindingContextHandle_t CreateContext( char const *filename, char const *pathID )
	{
		KBContext_t entry;

		entry.m_Handle = (KeyBindingContextHandle_t)++m_nKeyBindingContexts;
		entry.m_KeyBindingsFile = filename;
		if ( pathID )
		{
			entry.m_KeyBindingsPathID = pathID;
		}
		else
		{
			entry.m_KeyBindingsPathID = UTL_INVAL_SYMBOL;
		}

		m_Bindings.Insert( entry );

		return entry.m_Handle;
	}

	void AddPanelToContext( KeyBindingContextHandle_t handle, Panel *panel )
	{
		if ( !panel->GetName() || !panel->GetName()[ 0 ] )
		{
			Warning( "Can't add Keybindings Context for unnamed panels\n" );
			return;
		}

		KBContext_t *entry = Find( handle );
		Assert( entry );
		if ( entry )
		{
			int idx = entry->m_Panels.Find( panel );
			if ( idx == entry->m_Panels.InvalidIndex() )
			{
				entry->m_Panels.AddToTail( panel );
			}
		}
	}

	void OnPanelDeleted( KeyBindingContextHandle_t handle, Panel *panel )
	{
		KBContext_t *kb = Find( handle );
		if ( kb )
		{
			kb->m_Panels.FindAndRemove( panel );
		}
	}
	
	KBContext_t *Find( KeyBindingContextHandle_t handle )
	{
		KBContext_t search;
		search.m_Handle = handle;
		int idx = m_Bindings.Find( search );
		if ( idx == m_Bindings.InvalidIndex() )
		{
			return NULL;
		}
		return &m_Bindings[ idx ];
	}

	char const *GetKeyBindingsFile( KeyBindingContextHandle_t handle )
	{
		KBContext_t *kb = Find( handle );
		if ( kb )
		{
			return kb->m_KeyBindingsFile.String();
		}
		Assert( 0 );
		return "";
	}

	char const *GetKeyBindingsFilePathID( KeyBindingContextHandle_t handle )
	{
		KBContext_t *kb = Find( handle );
		if ( kb )
		{
			return kb->m_KeyBindingsPathID.String();
		}
		Assert( 0 );
		return NULL;
	}

	int GetPanelsWithKeyBindingsCount( KeyBindingContextHandle_t handle )
	{
		KBContext_t *kb = Find( handle );
		if ( kb )
		{
			return kb->m_Panels.Count();
		}
		Assert( 0 );
		return 0;
	}

	//-----------------------------------------------------------------------------
	// Purpose: static method
	// Input  : index - 
	// Output : Panel
	//-----------------------------------------------------------------------------
	Panel *GetPanelWithKeyBindings( KeyBindingContextHandle_t handle, int index )
	{		
		KBContext_t *kb = Find( handle );
		if ( kb )
		{
			Assert( index >= 0 && index < kb->m_Panels.Count() );
			return kb->m_Panels[ index ];
		}
		Assert( 0 );
		return 0;
	}

	CUtlRBTree< KBContext_t, int >	m_Bindings;
	int m_nKeyBindingContexts;
};

static CKeyBindingsMgr g_KBMgr;

//-----------------------------------------------------------------------------
// Purpose: Static method to allocate a context
// Input  :  - 
// Output : KeyBindingContextHandle_t
//-----------------------------------------------------------------------------
KeyBindingContextHandle_t Panel::CreateKeyBindingsContext( char const *filename, char const *pathID /*=0*/ )
{
	return g_KBMgr.CreateContext( filename, pathID );
}

COMPILE_TIME_ASSERT( ( MOUSE_MIDDLE - MOUSE_LEFT ) == 2 );
Panel* Panel::m_sMousePressedPanels[] = { NULL, NULL, NULL };

//-----------------------------------------------------------------------------
// Purpose: static method
// Input  :  - 
// Output : int
//-----------------------------------------------------------------------------
int Panel::GetPanelsWithKeyBindingsCount( KeyBindingContextHandle_t handle )
{
	return g_KBMgr.GetPanelsWithKeyBindingsCount( handle );
}

//-----------------------------------------------------------------------------
// Purpose: static method
// Input  : index - 
// Output : Panel
//-----------------------------------------------------------------------------
Panel *Panel::GetPanelWithKeyBindings( KeyBindingContextHandle_t handle, int index )
{
	return g_KBMgr.GetPanelWithKeyBindings( handle, index );
}


//-----------------------------------------------------------------------------
// Returns the number of keybindings
//-----------------------------------------------------------------------------
int Panel::GetKeyMappingCount( )
{
	int nCount = 0;
	PanelKeyBindingMap *map = GetKBMap();
	while ( map )
	{
		nCount += map->entries.Count();
		map = map->baseMap;
	}
	return nCount;
}


//-----------------------------------------------------------------------------
// Purpose: static method.  Reverts key bindings for all registered panels (panels with keybindings actually
//  loaded from file
// Input  :  - 
//-----------------------------------------------------------------------------
void Panel::RevertKeyBindings( KeyBindingContextHandle_t handle )
{
	int c = GetPanelsWithKeyBindingsCount( handle );
	for ( int i = 0; i < c; ++i )
	{
		Panel *kbPanel = GetPanelWithKeyBindings( handle, i );
		Assert( kbPanel );
		kbPanel->RevertKeyBindingsToDefault();
	}
}

static void BufPrint( CUtlBuffer& buf, int level, char const *fmt, ... )
{
	char string[ 2048 ];
	va_list argptr;
	va_start( argptr, fmt );
	_vsnprintf( string, sizeof( string ) - 1, fmt, argptr );
	va_end( argptr );
	string[ sizeof( string ) - 1 ] = 0;

	while ( --level >= 0 )
	{
		buf.Printf( "    " );
	}
	buf.Printf( "%s", string );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : handle - 
//-----------------------------------------------------------------------------
void Panel::SaveKeyBindings( KeyBindingContextHandle_t handle )
{
	char const *filename = g_KBMgr.GetKeyBindingsFile( handle );
	char const *pathID = g_KBMgr.GetKeyBindingsFilePathID( handle );

	SaveKeyBindingsToFile( handle, filename, pathID );
}

//-----------------------------------------------------------------------------
// Purpose: static method.  Saves key binding files out for all keybindings
// Input  :  - 
//-----------------------------------------------------------------------------
void Panel::SaveKeyBindingsToFile( KeyBindingContextHandle_t handle, char const *filename, char const *pathID /*= 0*/ )
{
	CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );

	BufPrint( buf, 0, "keybindings\n" );
	BufPrint( buf, 0, "{\n" );

	int c = GetPanelsWithKeyBindingsCount( handle );
	for ( int i = 0; i < c; ++i )
	{
		Panel *kbPanel = GetPanelWithKeyBindings( handle, i );
		Assert( kbPanel );
		if ( !kbPanel )
			continue;

		Assert( kbPanel->GetName() );
		Assert( kbPanel->GetName()[ 0 ] );

		if ( !kbPanel->GetName() || !kbPanel->GetName()[ 0 ] )
			continue;
	
		BufPrint( buf, 1, "\"%s\"\n", kbPanel->GetName() );
		BufPrint( buf, 1, "{\n" );

		kbPanel->SaveKeyBindingsToBuffer( 2, buf );

		BufPrint( buf, 1, "}\n" );
	}

	BufPrint( buf, 0, "}\n" );

	if ( g_pFullFileSystem->FileExists( filename, pathID ) &&
		!g_pFullFileSystem->IsFileWritable( filename, pathID ) )
	{
		Warning( "Panel::SaveKeyBindings '%s' is read-only!!!\n", filename );
	}

	FileHandle_t h = g_pFullFileSystem->Open( filename, "wb", pathID );
	if ( FILESYSTEM_INVALID_HANDLE != h )
	{
		g_pFullFileSystem->Write( buf.Base(), buf.TellPut(), h );
		g_pFullFileSystem->Close( h );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : handle - 
//			*panelOfInterest - 
//-----------------------------------------------------------------------------
void Panel::LoadKeyBindingsForOnePanel( KeyBindingContextHandle_t handle, Panel *panelOfInterest )
{
	if ( !panelOfInterest )
		return;
	if ( !panelOfInterest->GetName() )
		return;
	if ( !panelOfInterest->GetName()[ 0 ] )
		return;

	char const *filename = g_KBMgr.GetKeyBindingsFile( handle );
	char const *pathID = g_KBMgr.GetKeyBindingsFilePathID( handle );

	KeyValues *kv = new KeyValues( "keybindings" );
	if ( kv->LoadFromFile( g_pFullFileSystem, filename, pathID ) )
	{
		int c = GetPanelsWithKeyBindingsCount( handle );
		for ( int i = 0; i < c; ++i )
		{
			Panel *kbPanel = GetPanelWithKeyBindings( handle, i );
			Assert( kbPanel );
		
			char const *panelName = kbPanel->GetName();
			if ( !panelName )
			{
				continue;
			}

			if ( Q_stricmp( panelOfInterest->GetName(), panelName ) )
				continue;

			KeyValues *subKey = kv->FindKey( panelName, false );
			if ( !subKey )
			{
				Warning( "Panel::ReloadKeyBindings:  Can't find entry for panel '%s'\n", panelName );
				continue;
			}
			
            kbPanel->ParseKeyBindings( subKey );
		}
	}
	kv->deleteThis();
}

//-----------------------------------------------------------------------------
// Purpose: static method.  Loads all key bindings again
// Input  :  - 
//-----------------------------------------------------------------------------

void Panel::ReloadKeyBindings( KeyBindingContextHandle_t handle )
{
	char const *filename = g_KBMgr.GetKeyBindingsFile( handle );
	char const *pathID = g_KBMgr.GetKeyBindingsFilePathID( handle );

	KeyValues *kv = new KeyValues( "keybindings" );
	if ( kv->LoadFromFile( g_pFullFileSystem, filename, pathID ) )
	{
		int c = GetPanelsWithKeyBindingsCount( handle );
		for ( int i = 0; i < c; ++i )
		{
			Panel *kbPanel = GetPanelWithKeyBindings( handle, i );
			Assert( kbPanel );
		
			char const *panelName = kbPanel->GetName();
			if ( !panelName )
			{
				continue;
			}

			KeyValues *subKey = kv->FindKey( panelName, false );
			if ( !subKey )
			{
				Warning( "Panel::ReloadKeyBindings:  Can't find entry for panel '%s'\n", panelName );
				continue;
			}
			
            kbPanel->ParseKeyBindings( subKey );
		}
	}
	kv->deleteThis();
}
#endif // VGUI_USEKEYBINDINGMAPS

DECLARE_BUILD_FACTORY( Panel );

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
Panel::Panel()
{
	Init(0, 0, 64, 24);
}

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
Panel::Panel(Panel *parent)
{
	Init(0, 0, 64, 24);
	SetParent(parent);
}

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
Panel::Panel(Panel *parent, const char *panelName)
{
	Init(0, 0, 64, 24);
	SetName(panelName);
	SetParent(parent);
	SetBuildModeEditable(true);
}

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
Panel::Panel( Panel *parent, const char *panelName, HScheme scheme )
{
	Init(0, 0, 64, 24);
	SetName(panelName);
	SetParent(parent);
	SetBuildModeEditable(true);
	SetScheme( scheme );
}

//-----------------------------------------------------------------------------
// Purpose: Setup
//-----------------------------------------------------------------------------
void Panel::Init( int x, int y, int wide, int tall )
{
	_panelName = NULL;
	_tooltipText = NULL;
	_pinToSibling = NULL;
	m_hMouseEventHandler = NULL;
	_pinCornerToSibling = PIN_TOPLEFT;
	_pinToSiblingCorner = PIN_TOPLEFT;

	// get ourselves an internal panel
	_vpanel = ivgui()->AllocPanel();
	ipanel()->Init(_vpanel, this);

	SetPos(x, y);
	SetSize(wide, tall);
	_flags.SetFlag( NEEDS_LAYOUT | NEEDS_SCHEME_UPDATE | NEEDS_DEFAULT_SETTINGS_APPLIED );
	_flags.SetFlag( AUTODELETE_ENABLED | PAINT_BORDER_ENABLED | PAINT_BACKGROUND_ENABLED | PAINT_ENABLED );
#if defined( VGUI_USEKEYBINDINGMAPS )
	_flags.SetFlag( ALLOW_CHAIN_KEYBINDING_TO_PARENT );
#endif
	m_nPinDeltaX = m_nPinDeltaY = 0;
	m_nResizeDeltaX = m_nResizeDeltaY = 0;
	_autoResizeDirection = AUTORESIZE_NO;
	_pinCorner = PIN_TOPLEFT;
	_cursor = dc_arrow;
	_border = NULL;
	_buildGroup = UTLHANDLE_INVALID;
	_tabPosition = 0;
	m_iScheme = 0;
	m_bIsSilent = false;
	m_bParentNeedsCursorMoveEvents = false;

	_buildModeFlags = 0; // not editable or deletable in buildmode dialog by default

	m_pTooltips = NULL;
	m_bToolTipOverridden = false;

	m_flAlpha = 255.0f;
	m_nPaintBackgroundType = 0;

	//=============================================================================
	// HPE_BEGIN:
	// [tj] Default to rounding all corners (for draw style 2)
	//=============================================================================
	m_roundedCorners = PANEL_ROUND_CORNER_ALL;
	//=============================================================================
	// HPE_END
	//=============================================================================

	m_nBgTextureId1 = -1;
	m_nBgTextureId2 = -1;
	m_nBgTextureId3 = -1;
	m_nBgTextureId4 = -1;
#if defined( VGUI_USEDRAGDROP )
	m_pDragDrop = new DragDrop_t;

#endif

	m_lLastDoublePressTime = 0L;

#if defined( VGUI_USEKEYBINDINGMAPS )
	m_hKeyBindingsContext = INVALID_KEYBINDINGCONTEXT_HANDLE;
#endif

	REGISTER_COLOR_AS_OVERRIDABLE( _fgColor, "fgcolor_override" );
	REGISTER_COLOR_AS_OVERRIDABLE( _bgColor, "bgcolor_override" );

	m_bIsConsoleStylePanel = false;
	m_NavUp = NULL;
	m_NavDown = NULL;
	m_NavLeft = NULL;
	m_NavRight = NULL;
	m_NavToRelay = NULL;
	m_NavActivate = NULL;
	m_NavBack = NULL;
	m_sNavUpName = NULL;
	m_sNavDownName = NULL;
	m_sNavLeftName = NULL;
	m_sNavRightName = NULL;
	m_sNavToRelayName = NULL;
	m_sNavActivateName = NULL;
	m_sNavBackName = NULL;

	m_PassUnhandledInput = true;
	m_LastNavDirection = ND_NONE;
	m_bWorldPositionCurrentFrame = false;
	m_bForceStereoRenderToFrameBuffer = false;
}

//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
Panel::~Panel()
{
	// @note Tom Bui: only cleanup if we've created it
	if ( !m_bToolTipOverridden )
	{
		if ( m_pTooltips )
		{
			delete m_pTooltips;
		}
	}
#if defined( VGUI_USEKEYBINDINGMAPS )
	if ( IsValidKeyBindingsContext() )
	{
		g_KBMgr.OnPanelDeleted( m_hKeyBindingsContext, this );
	}
#endif // VGUI_USEKEYBINDINGMAPS
#if defined( VGUI_USEDRAGDROP )
	if ( m_pDragDrop->m_bDragging )
	{
		OnFinishDragging( false, (MouseCode)-1 );
	}
#endif // VGUI_USEDRAGDROP

	_flags.ClearFlag( AUTODELETE_ENABLED );
	_flags.SetFlag( MARKED_FOR_DELETION );

	// remove panel from any list
	SetParent((VPANEL)NULL);

	// Stop our children from pointing at us, and delete them if possible
	while (ipanel()->GetChildCount(GetVPanel()))
	{
		VPANEL child = ipanel()->GetChild(GetVPanel(), 0);
		if (ipanel()->IsAutoDeleteSet(child))
		{
			ipanel()->DeletePanel(child);
		}
		else
		{
			ipanel()->SetParent(child, NULL);
		}
	}

	// delete VPanel
	ivgui()->FreePanel(_vpanel);
	// free our name
	delete [] _panelName;

	if ( _tooltipText && _tooltipText[0] )
	{
		delete [] _tooltipText;
	}

	delete [] _pinToSibling;

	_vpanel = NULL;
#if defined( VGUI_USEDRAGDROP )
	delete m_pDragDrop;
#endif // VGUI_USEDRAGDROP

#if defined( VGUI_PANEL_VERIFY_DELETES )
	// Zero out our vtbl pointer. This should hopefully help us catch bad guys using
	//  this panel after it has been deleted.
	uintp *panel_vtbl = (uintp *)this;
	*panel_vtbl = NULL;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: fully construct this panel so its ready for use right now (i.e fonts loaded, colors set, default label text set, ...)
//-----------------------------------------------------------------------------
void Panel::MakeReadyForUse()
{
//	PerformApplySchemeSettings();
	UpdateSiblingPin();
	surface()->SolveTraverse( GetVPanel(), true );
}

	
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::SetName( const char *panelName )
{
	// No change?
	if ( _panelName && 
		panelName && 
		!Q_strcmp( _panelName, panelName ) )
	{
		return;
	}

	if (_panelName)
	{
		delete [] _panelName;
		_panelName = NULL;
	}

	if (panelName)
	{
		int len = Q_strlen(panelName) + 1;
		_panelName = new char[ len ];
		Q_strncpy( _panelName, panelName, len );
	}
}

//-----------------------------------------------------------------------------
// Purpose: returns the given name of the panel
//-----------------------------------------------------------------------------
const char *Panel::GetName()
{
	if (_panelName)
		return _panelName;

	return "";
}

//-----------------------------------------------------------------------------
// Purpose: returns the name of the module that this instance of panel was compiled into
//-----------------------------------------------------------------------------
const char *Panel::GetModuleName()
{
	return vgui::GetControlsModuleName();
}

//-----------------------------------------------------------------------------
// Purpose: returns the classname of the panel (as specified in the panelmaps)
//-----------------------------------------------------------------------------
const char *Panel::GetClassName()
{
	// loop up the panel map name
	PanelMessageMap *panelMap = GetMessageMap();
	if ( panelMap && panelMap->pfnClassName )
	{
		return panelMap->pfnClassName();
	}

	return "Panel";
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::SetPos(int x, int y)
{
	if ( !HushAsserts() )
	{
		Assert( abs(x) < 32768 && abs(y) < 32768 );
	}
	ipanel()->SetPos(GetVPanel(), x, y);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::GetPos(int &x, int &y)
{
	ipanel()->GetPos(GetVPanel(), x, y);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int Panel::GetXPos()
{
	int x,y;
	GetPos( x, y );
	return x;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int Panel::GetYPos()
{
	int x,y;
	GetPos( x, y );
	return y;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::SetSize(int wide, int tall)
{
	tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s", __FUNCTION__, GetName() );
	Assert( abs(wide) < 32768 && abs(tall) < 32768 );
	ipanel()->SetSize(GetVPanel(), wide, tall);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::GetSize(int &wide, int &tall)
{
	ipanel()->GetSize(GetVPanel(), wide, tall);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::SetBounds(int x, int y, int wide, int tall)
{
	SetPos(x,y);
	SetSize(wide,tall);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::GetBounds(int &x, int &y, int &wide, int &tall)
{
	GetPos(x, y);
	GetSize(wide, tall);
}

//-----------------------------------------------------------------------------
// Purpose: returns safe handle to parent
//-----------------------------------------------------------------------------
VPANEL Panel::GetVParent()
{
    if ( ipanel() )
    {
	    return ipanel()->GetParent(GetVPanel());
    }

    return 0;
}

//-----------------------------------------------------------------------------
// Purpose: returns a pointer to a controls version of a Panel pointer
//-----------------------------------------------------------------------------
Panel *Panel::GetParent()
{
	// get the parent and convert it to a Panel *
	// this is OK, the hierarchy is guaranteed to be all from the same module, except for the root node
	// the root node always returns NULL when a GetParent() is done so everything is OK
    if ( ipanel() )
    {
	    VPANEL parent = ipanel()->GetParent(GetVPanel());
	    if (parent)
	    {
		    Panel *pParent = ipanel()->GetPanel(parent, GetControlsModuleName());
		    Assert(!pParent || !strcmp(pParent->GetModuleName(), GetControlsModuleName()));
		    return pParent;
	    }
	}

	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose: Screen size change notification handler
//-----------------------------------------------------------------------------
void Panel::OnScreenSizeChanged(int nOldWide, int nOldTall)
{
	// post to all children
	for (int i = 0; i < ipanel()->GetChildCount(GetVPanel()); i++)
	{
		VPANEL child = ipanel()->GetChild(GetVPanel(), i);
		PostMessage(child, new KeyValues("OnScreenSizeChanged", "oldwide", nOldWide, "oldtall", nOldTall), NULL);
	}

	// make any currently fullsize window stay fullsize
	int x, y, wide, tall;
	GetBounds(x, y, wide, tall);
	int screenWide, screenTall;
	surface()->GetScreenSize(screenWide, screenTall);
	if (x == 0 && y == 0 && nOldWide == wide && tall == nOldTall)
	{
		// fullsize
		surface()->GetScreenSize(wide, tall);
		SetBounds(0, 0, wide, tall);
	}

	// panel needs to re-get it's scheme settings
	_flags.SetFlag( NEEDS_SCHEME_UPDATE );

	// invalidate our settings
	InvalidateLayout();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::SetVisible(bool state)
{
	ipanel()->SetVisible(GetVPanel(), state);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool Panel::IsVisible()
{
    if (ipanel())
    {
	    return ipanel()->IsVisible(GetVPanel());
    }

    return false;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::SetEnabled(bool state)
{
	if (state != ipanel()->IsEnabled( GetVPanel()))
	{
		ipanel()->SetEnabled(GetVPanel(), state);
		InvalidateLayout(false);
		Repaint();
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool Panel::IsEnabled()
{
	return ipanel()->IsEnabled(GetVPanel());
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool Panel::IsPopup()
{
	return ipanel()->IsPopup(GetVPanel());
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::Repaint()
{
	_flags.SetFlag( NEEDS_REPAINT );
    if (surface())
    {
        surface()->Invalidate(GetVPanel());
    }
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::Think()
{
	if (IsVisible())
	{	
		// update any tooltips
		if (m_pTooltips)
		{
			m_pTooltips->PerformLayout();
		}
		if ( _flags.IsFlagSet( NEEDS_LAYOUT ) )
		{
			InternalPerformLayout();
		}
	}

	OnThink();
}

void Panel::OnChildSettingsApplied( KeyValues *pInResourceData, Panel *pChild  )
{
	tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s", __FUNCTION__, GetName() );

	Panel* pParent = GetParent();
	if( pParent )
	{
		pParent->OnChildSettingsApplied( pInResourceData, pChild );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::PaintTraverse( bool repaint, bool allowForce )
{
	if ( m_bWorldPositionCurrentFrame )
	{
		surface()->SolveTraverse( GetVPanel() );
	}

	if ( !IsVisible() )
	{
		return;
	}

	float oldAlphaMultiplier = surface()->DrawGetAlphaMultiplier();
	float newAlphaMultiplier = oldAlphaMultiplier * m_flAlpha * 1.0f/255.0f;

	if ( IsXbox() && !newAlphaMultiplier )
	{
		// xbox optimization not suitable for pc
		// xbox panels are compliant and can early out and not traverse their children
		// when they have no opacity
		return;
	}

	if ( !repaint &&
		 allowForce &&
		 _flags.IsFlagSet( NEEDS_REPAINT ) )
	{
		repaint = true;
		_flags.ClearFlag( NEEDS_REPAINT );
	}

	VPANEL vpanel = GetVPanel();

	bool bPushedViewport = false;
	if( GetForceStereoRenderToFrameBuffer()  )
	{
		CMatRenderContextPtr pRenderContext( materials );
		if( pRenderContext->GetRenderTarget() )
		{
			surface()->PushFullscreenViewport();
			bPushedViewport = true;
		}
	}

	int clipRect[4];
	ipanel()->GetClipRect( vpanel, clipRect[0], clipRect[1], clipRect[2], clipRect[3] );
	if ( ( clipRect[2] <= clipRect[0] ) || ( clipRect[3] <= clipRect[1] ) )
	{
		repaint = false;
	}

	// set global alpha
	surface()->DrawSetAlphaMultiplier( newAlphaMultiplier );

	bool bBorderPaintFirst = _border ? _border->PaintFirst() : false;

	// draw the border first if requested to
	if ( bBorderPaintFirst && repaint && _flags.IsFlagSet( PAINT_BORDER_ENABLED ) && ( _border != null ) )
	{
		// Paint the border over the background with no inset
		surface()->PushMakeCurrent( vpanel, false );
		PaintBorder();
		surface()->PopMakeCurrent( vpanel );
	}

	if ( repaint )
	{
		// draw the background with no inset
		if ( _flags.IsFlagSet( PAINT_BACKGROUND_ENABLED ) )
		{
			surface()->PushMakeCurrent( vpanel, false );
			PaintBackground();
			surface()->PopMakeCurrent( vpanel );
		}

		// draw the front of the panel with the inset
		if ( _flags.IsFlagSet( PAINT_ENABLED ) )
		{
			surface()->PushMakeCurrent( vpanel, true );
			Paint();
			surface()->PopMakeCurrent( vpanel );
		}
	}

	// traverse and paint all our children
	CUtlVector< VPANEL > &children = ipanel()->GetChildren( vpanel );
	int childCount = children.Count();
	for (int i = 0; i < childCount; i++)
	{
		VPANEL child = children[ i ];
		bool bVisible = ipanel()->IsVisible( child );

		if ( surface()->ShouldPaintChildPanel( child ) )
		{
			if ( bVisible )
			{
				ipanel()->PaintTraverse( child, repaint, allowForce );
			}
		}
		else
		{
			// Invalidate the child panel so that it gets redrawn
			surface()->Invalidate( child );

			// keep traversing the tree, just don't allow anyone to paint after here
			if ( bVisible )
			{
				ipanel()->PaintTraverse( child, false, false );
			}
		}
	}

	// draw the border last
	if ( repaint )
	{
		if ( !bBorderPaintFirst && _flags.IsFlagSet( PAINT_BORDER_ENABLED ) && ( _border != null ) )
		{
			// Paint the border over the background with no inset
			surface()->PushMakeCurrent( vpanel, false );
			PaintBorder();
			surface()->PopMakeCurrent( vpanel );
		}

#ifdef _DEBUG
		// IsBuildGroupEnabled recurses up all the parents and ends up being very expensive as it wanders all over memory
		if ( GetBuildModeDialogCount() && IsBuildGroupEnabled() ) //&& HasFocus() )
		{
			// outline all selected panels 
			// outline all selected panels 
			CUtlVector<PHandle> *controlGroup = _buildGroup->GetControlGroup();
			for (int i=0; i < controlGroup->Size(); ++i)
			{
				surface()->PushMakeCurrent( ((*controlGroup)[i].Get())->GetVPanel(), false );
				((*controlGroup)[i].Get())->PaintBuildOverlay();
				surface()->PopMakeCurrent( ((*controlGroup)[i].Get())->GetVPanel() );
			}	
			
			_buildGroup->DrawRulers();						
		}
#endif

		// All of our children have painted, etc, now allow painting in top of them
		if ( _flags.IsFlagSet( POST_CHILD_PAINT_ENABLED ) )
		{
			surface()->PushMakeCurrent( vpanel, false );
			PostChildPaint();
			surface()->PopMakeCurrent( vpanel );
		}
	}

	surface()->DrawSetAlphaMultiplier( oldAlphaMultiplier );

	surface()->SwapBuffers( vpanel );

	if( bPushedViewport )
	{
		surface()->PopFullscreenViewport();
	}
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::PaintBorder()
{
	_border->Paint(GetVPanel());
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::PaintBackground()
{ 
	int wide, tall;
	GetSize( wide, tall );
	if ( m_SkipChild.Get() && m_SkipChild->IsVisible() )
	{
		if ( GetPaintBackgroundType() == 2 )
		{
			int cornerWide, cornerTall;
			GetCornerTextureSize( cornerWide, cornerTall );

			Color col = GetBgColor();
			DrawHollowBox( 0, 0, wide, tall, col, 1.0f );

			wide -= 2 * cornerWide;
			tall -= 2 * cornerTall;

			FillRectSkippingPanel( GetBgColor(), cornerWide, cornerTall, wide, tall, m_SkipChild.Get() );
		}
		else
		{
			FillRectSkippingPanel( GetBgColor(), 0, 0, wide, tall, m_SkipChild.Get() );
		}
	}
	else
	{
		Color col = GetBgColor();

		switch ( m_nPaintBackgroundType )
		{
		default:
		case 0:
			{
				surface()->DrawSetColor(col);
				surface()->DrawFilledRect(0, 0, wide, tall);
			}
			break;
		case 1:
			{
				DrawTexturedBox( 0, 0, wide, tall, col, 1.0f );
			}
			break;
		case 2:
			{
				DrawBox( 0, 0, wide, tall, col, 1.0f );
			}
			break;
		case 3:
			{
				DrawBoxFade( 0, 0, wide, tall, col, 1.0f, 255, 0, true );
			}
			break;
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::Paint()
{
	// empty on purpose
	// PaintBackground is painted and default behavior is for Paint to do nothing
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::PostChildPaint()
{
	// Empty on purpose
	// This is called if _postChildPaintEnabled is true and allows painting to
	//  continue on the surface after all of the panel's children have painted 
	//  themselves.  Allows drawing an overlay on top of the children, etc.
}

//-----------------------------------------------------------------------------
// Purpose: Draws a black rectangle around the panel.
//-----------------------------------------------------------------------------
void Panel::PaintBuildOverlay()
{
	int wide,tall;
	GetSize(wide,tall);
	surface()->DrawSetColor(0, 0, 0, 255);

	surface()->DrawFilledRect(0,0,wide,2);           //top
	surface()->DrawFilledRect(0,tall-2,wide,tall);   //bottom
	surface()->DrawFilledRect(0,2,2,tall-2);         //left
	surface()->DrawFilledRect(wide-2,2,wide,tall-2); //right
}

//-----------------------------------------------------------------------------
// Purpose: Returns true if the panel's draw code will fully cover it's area
//-----------------------------------------------------------------------------
bool Panel::IsOpaque()
{
	// FIXME: Add code to account for the 'SkipChild' functionality in Frame
	if ( IsVisible() && _flags.IsFlagSet( PAINT_BACKGROUND_ENABLED ) && ( _bgColor[3] == 255 ) )
		return true;

	return false;
}

//-----------------------------------------------------------------------------
// Purpose: returns true if the settings are aligned to the right of the screen
//-----------------------------------------------------------------------------
bool Panel::IsRightAligned()
{
	return (_buildModeFlags & BUILDMODE_SAVE_XPOS_RIGHTALIGNED);
}

//-----------------------------------------------------------------------------
// Purpose: returns true if the settings are aligned to the bottom of the screen
//-----------------------------------------------------------------------------
bool Panel::IsBottomAligned()
{
	return (_buildModeFlags & BUILDMODE_SAVE_YPOS_BOTTOMALIGNED);
}

//-----------------------------------------------------------------------------
// Purpose: sets the parent
//-----------------------------------------------------------------------------
void Panel::SetParent(Panel *newParent)
{
	// Assert that the parent is from the same module as the child
	// FIXME: !!! work out how to handle this properly!
	//	Assert(!newParent || !strcmp(newParent->GetModuleName(), GetControlsModuleName()));

	Panel* pCurrentParent = GetParent();
	if ( pCurrentParent )
	{
		pCurrentParent->m_dictChidlren.Remove( GetName() );
	}

	if (newParent)
	{
		SetParent(newParent->GetVPanel());
	}
	else
	{
		SetParent((VPANEL)NULL);
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::SetParent(VPANEL newParent)
{

	if (newParent)
	{

		ipanel()->SetParent(GetVPanel(), newParent);
	}
	else
	{
		ipanel()->SetParent(GetVPanel(), NULL);
	}

	if (GetVParent() )
	{
		if( ipanel()->IsProportional(GetVParent()) )
			SetProportional(true);

		if( !IsPopup() )
		{
			// most of the time KBInput == parents kbinput
			if (ipanel()->IsKeyBoardInputEnabled(GetVParent()) != IsKeyBoardInputEnabled())
				SetKeyBoardInputEnabled(ipanel()->IsKeyBoardInputEnabled(GetVParent()));

			if (ipanel()->IsMouseInputEnabled(GetVParent()) != IsMouseInputEnabled())
				SetMouseInputEnabled(ipanel()->IsMouseInputEnabled(GetVParent()));
		}
	}

	UpdateSiblingPin();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::OnChildAdded(VPANEL child)
{
	Assert( !_flags.IsFlagSet( IN_PERFORM_LAYOUT ) );
	Panel *pChild = ipanel()->GetPanel(child, GetControlsModuleName());
	if ( pChild )
	{
		auto idx = m_dictChidlren.Insert( pChild->GetName() );
		m_dictChidlren[ idx ].Set( child );
	}
}

//-----------------------------------------------------------------------------
// Purpose: default message handler
//-----------------------------------------------------------------------------
void Panel::OnSizeChanged(int newWide, int newTall)
{
	InvalidateLayout(); // our size changed so force us to layout again
}

//-----------------------------------------------------------------------------
// Purpose: sets Z ordering - lower numbers are always behind higher z's
//-----------------------------------------------------------------------------
void Panel::SetZPos(int z)
{
	ipanel()->SetZPos(GetVPanel(), z);
}

//-----------------------------------------------------------------------------
// Purpose: sets Z ordering - lower numbers are always behind higher z's
//-----------------------------------------------------------------------------
int Panel::GetZPos() const
{
	return ( ipanel()->GetZPos( GetVPanel() ) );
}

//-----------------------------------------------------------------------------
// Purpose: sets alpha modifier for panel and all child panels [0..255]
//-----------------------------------------------------------------------------
void Panel::SetAlpha(int alpha)
{
	m_flAlpha = alpha;
}

//-----------------------------------------------------------------------------
// Purpose: data accessor
//-----------------------------------------------------------------------------
int Panel::GetAlpha()
{
	return (int)m_flAlpha;
}

//-----------------------------------------------------------------------------
// Purpose: Moves the panel to the front of the z-order
//-----------------------------------------------------------------------------
void Panel::MoveToFront(void)
{
	// FIXME: only use ipanel() as per src branch?
	if (IsPopup())
	{
		surface()->BringToFront(GetVPanel());
	}
	else
	{
		ipanel()->MoveToFront(GetVPanel());
	}
}

//-----------------------------------------------------------------------------
// Purpose: Iterates up the hierarchy looking for a particular parent
//-----------------------------------------------------------------------------
bool Panel::HasParent(VPANEL potentialParent)
{
	if (!potentialParent)
		return false;

	return ipanel()->HasParent(GetVPanel(), potentialParent);
}

//-----------------------------------------------------------------------------
// Purpose: Finds the index of a child panel by string name
// Output : int - -1 if no panel of that name is found
//-----------------------------------------------------------------------------
int Panel::FindChildIndexByName(const char *childName)
{
	for (int i = 0; i < GetChildCount(); i++)
	{
		Panel *pChild = GetChild(i);
		if (!pChild)
			continue;

		if (!stricmp(pChild->GetName(), childName))
		{
			return i;
		}
	}

	return -1;
}

//-----------------------------------------------------------------------------
// Purpose: Finds a child panel by string name
// Output : Panel * - NULL if no panel of that name is found
//-----------------------------------------------------------------------------
Panel *Panel::FindChildByName(const char *childName, bool recurseDown)
{
	tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s finding %s", __FUNCTION__, GetName(), childName );

	auto idx = m_dictChidlren.Find( childName );
	if ( idx != m_dictChidlren.InvalidIndex() )
	{
		Panel *pCachedChild = ipanel()->GetPanel( m_dictChidlren[ idx ], GetControlsModuleName() );
		
		if ( !pCachedChild )
		{
			m_dictChidlren.Remove( childName );
		}
		else
		{
			return pCachedChild;
		}
	}

	for (int i = 0; i < GetChildCount(); i++)
	{
		Panel *pChild = GetChild(i);
		if (!pChild)
			continue;

		if (!V_stricmp(pChild->GetName(), childName))
		{
			idx = m_dictChidlren.Insert( childName );
			m_dictChidlren[ idx ].Set( pChild->GetVPanel() );
			return pChild;
		}

		if (recurseDown)
		{
			Panel *panel = pChild->FindChildByName(childName, recurseDown);
			if ( panel )
			{
				return panel;
			}
		}
	}

	m_dictChidlren.Insert( childName ); // Defaults the handle to INVALID_PANEL
	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose: Finds a sibling panel by name
//-----------------------------------------------------------------------------
Panel *Panel::FindSiblingByName(const char *siblingName)
{
	if ( !GetVParent() )
		return NULL;

	int siblingCount = ipanel()->GetChildCount(GetVParent());
	for (int i = 0; i < siblingCount; i++)
	{
		VPANEL sibling = ipanel()->GetChild(GetVParent(), i);
		Panel *panel = ipanel()->GetPanel(sibling, GetControlsModuleName());
		if (!stricmp(panel->GetName(), siblingName))
		{
			return panel;
		}
	}

	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose: Dispatches immediately a message to the parent
//-----------------------------------------------------------------------------
void Panel::CallParentFunction(KeyValues *message)
{
	if (GetVParent())
	{
		ipanel()->SendMessage(GetVParent(), message, GetVPanel());
	}
	if (message)
	{
		message->deleteThis();
	}
}

//-----------------------------------------------------------------------------
// Purpose: if set to true, panel automatically frees itself when parent is deleted
//-----------------------------------------------------------------------------
void Panel::SetAutoDelete( bool state )
{
	_flags.SetFlag( AUTODELETE_ENABLED, state );
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool Panel::IsAutoDeleteSet()
{
	return _flags.IsFlagSet( AUTODELETE_ENABLED );
}


//-----------------------------------------------------------------------------
// Purpose: Just calls 'delete this'
//-----------------------------------------------------------------------------
void Panel::DeletePanel()
{
	// Avoid re-entrancy
	_flags.SetFlag( MARKED_FOR_DELETION );
	_flags.ClearFlag( AUTODELETE_ENABLED );
	delete this;
}

//-----------------------------------------------------------------------------
// Purpose: data accessor
//-----------------------------------------------------------------------------
HScheme Panel::GetScheme()
{
	if (m_iScheme)
	{
		return m_iScheme; // return our internal scheme
	}
	
	if (GetVParent()) // recurse down the heirarchy 
	{
		return ipanel()->GetScheme(GetVParent());
	}

	return scheme()->GetDefaultScheme();
}

//-----------------------------------------------------------------------------
// Purpose: set the scheme to render this panel with by name
//-----------------------------------------------------------------------------
void Panel::SetScheme(const char *tag)
{
	if (strlen(tag) > 0 && scheme()->GetScheme(tag)) // check the scheme exists
	{
		SetScheme(scheme()->GetScheme(tag));
	}
}

//-----------------------------------------------------------------------------
// Purpose: set the scheme to render this panel with 
//-----------------------------------------------------------------------------
void Panel::SetScheme(HScheme scheme)
{
	if (scheme != m_iScheme)
	{
		m_iScheme = scheme;

		// This will cause the new scheme to be applied at a later point
//		InvalidateLayout( false, true );
	}
}


//-----------------------------------------------------------------------------
// Purpose: returns the char of this panels hotkey
//-----------------------------------------------------------------------------
Panel *Panel::HasHotkey(wchar_t key)
{
	return NULL;
}

#if defined( VGUI_USEDRAGDROP )
static vgui::PHandle	g_DragDropCapture;
#endif // VGUI_USEDRAGDROP

void Panel::InternalCursorMoved(int x, int y)
{
#if defined( VGUI_USEDRAGDROP )
	if ( g_DragDropCapture.Get() )
	{
		bool started = g_DragDropCapture->GetDragDropInfo()->m_bDragStarted;

		g_DragDropCapture->OnContinueDragging();

		if ( started )
		{
			bool isEscapeKeyDown = input()->IsKeyDown( KEY_ESCAPE );
			if ( isEscapeKeyDown )
			{
				g_DragDropCapture->OnFinishDragging( true, (MouseCode)-1, true );
			}
			return;
		}
	}
#endif // VGUI_USEDRAGDROP

	if ( !ShouldHandleInputMessage() )
		return;

	if ( IsCursorNone() )
		return;
	
	if ( !IsMouseInputEnabled() )
	{
		return;
	}

	if (IsBuildGroupEnabled())
	{
		if ( _buildGroup->CursorMoved(x, y, this) )
		{
			return;
		}
	}

	if (m_pTooltips)
	{
		if ( _tooltipText )
		{
			m_pTooltips->SetText( _tooltipText );
		}
		m_pTooltips->ShowTooltip(this);
	}

	ScreenToLocal(x, y);

	OnCursorMoved(x, y);
}

void Panel::InternalCursorEntered()
{
	if (IsCursorNone() || !IsMouseInputEnabled())
		return;
	
	if (IsBuildGroupEnabled())
		return;

	if (m_pTooltips)
	{
		m_pTooltips->ResetDelay();

		if ( _tooltipText )
		{
			m_pTooltips->SetText( _tooltipText );
		}
		m_pTooltips->ShowTooltip(this);
	}

	OnCursorEntered();
}

void Panel::InternalCursorExited()
{
	if (IsCursorNone() || !IsMouseInputEnabled())
		return;
	
	if (IsBuildGroupEnabled())
		return;

	if (m_pTooltips)
	{
		m_pTooltips->HideTooltip();
	}

	OnCursorExited();
}

bool Panel::IsChildOfSurfaceModalPanel()
{
	VPANEL appModalPanel = input()->GetAppModalSurface();
	if ( !appModalPanel )
		return true;

	if ( ipanel()->HasParent( GetVPanel(), appModalPanel ) )
		return true;

	return false;
}


//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool Panel::IsChildOfModalSubTree()
{
	VPANEL subTree = input()->GetModalSubTree();
	if ( !subTree )
		return true;

	if ( HasParent( subTree ) )
		return true;

	return false;
}

//-----------------------------------------------------------------------------
// Purpose: Checks to see if message is being subverted due to modal subtree logic
// Input  :  - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
static bool ShouldHandleInputMessage( VPANEL p )
{
	// If there is not modal subtree, then always handle the msg
	if ( !input()->GetModalSubTree() )
		return true;

	// What state are we in?
	bool bChildOfModal = false;
	VPANEL subTree = input()->GetModalSubTree();
	if ( !subTree )
	{
		bChildOfModal = true;
	}
	else if ( ipanel()->HasParent( p, subTree ) )
	{
		bChildOfModal = true;
	}

	if ( input()->ShouldModalSubTreeReceiveMessages() )
		return bChildOfModal;

	return !bChildOfModal;
}

bool Panel::ShouldHandleInputMessage()
{
	return ::ShouldHandleInputMessage( GetVPanel() );
}

void Panel::InternalMousePressed(int code)
{
	long curtime = system()->GetTimeMillis();
	if ( IsTriplePressAllowed() )
	{
		long elapsed = curtime - m_lLastDoublePressTime;
		if ( elapsed < TRIPLE_PRESS_MSEC )
		{
			InternalMouseTriplePressed( code );
			return;
		}
	}

	// The menu system passively watches for mouse released messages so it 
	// can clear any open menus if the release is somewhere other than on a menu
	Menu::OnInternalMousePressed( this, (MouseCode)code );

	if ( !ShouldHandleInputMessage() )
		return;

	if ( IsCursorNone() )
		return;
	
	if ( !IsMouseInputEnabled())
	{
#if defined( VGUI_USEDRAGDROP )
		DragDropStartDragging();
#endif
		return;
	}
	
	if (IsBuildGroupEnabled())
	{
		if ( _buildGroup->MousePressed((MouseCode)code, this) )
		{
			return;
		}
	}

#ifdef STAGING_ONLY
	// If holding CTRL + ALT, invalidate layout.  For debugging purposes
	if ( ( vgui::input()->IsKeyDown(KEY_LCONTROL) || vgui::input()->IsKeyDown(KEY_RCONTROL) ) 
		&& ( vgui::input()->IsKeyDown(KEY_LALT) || vgui::input()->IsKeyDown(KEY_RALT) ) )
	{
		InvalidateLayout( true, true );
	}
#endif

#ifdef STAGING_ONLY
	const char *pGameDir = CommandLine()->ParmValue( "-game", "hl2" );
	if ( !V_stricmp( pGameDir, "tf" ) )
	{
		if ( code >= MOUSE_LEFT && code <= MOUSE_MIDDLE )
		{
			m_sMousePressedPanels[ code - MOUSE_LEFT ] = this;
		}
	}
#endif

	Panel *pMouseHandler = m_hMouseEventHandler.Get();
	if ( pMouseHandler )
	{
		pMouseHandler->OnMousePressed( (MouseCode)code );
	}
	else
	{
		OnMousePressed( (MouseCode)code );
	}

#if defined( VGUI_USEDRAGDROP )
	DragDropStartDragging();
#endif
}

void Panel::InternalMouseDoublePressed(int code)
{
	m_lLastDoublePressTime = system()->GetTimeMillis();

	if ( !ShouldHandleInputMessage() )
		return;

	if ( IsCursorNone() )
		return;
	
	if ( !IsMouseInputEnabled())
	{
		return;
	}
	
	if (IsBuildGroupEnabled())
	{
		if ( _buildGroup->MouseDoublePressed((MouseCode)code, this) )
		{
			return;
		}
	}

	Panel *pMouseHandler = m_hMouseEventHandler.Get();
	if ( pMouseHandler )
	{
		pMouseHandler->OnMouseDoublePressed( (MouseCode)code );
	}
	else
	{
		OnMouseDoublePressed( (MouseCode)code );
	}
}

#if defined( VGUI_USEDRAGDROP )
void Panel::SetStartDragWhenMouseExitsPanel( bool state )
{
	_flags.SetFlag( DRAG_REQUIRES_PANEL_EXIT, state );
}

bool Panel::IsStartDragWhenMouseExitsPanel() const
{
	return 	_flags.IsFlagSet( DRAG_REQUIRES_PANEL_EXIT );
}
#endif // VGUI_USEDRAGDROP

void Panel::SetTriplePressAllowed( bool state )
{
	_flags.SetFlag( TRIPLE_PRESS_ALLOWED, state );
}

bool Panel::IsTriplePressAllowed() const
{
	return 	_flags.IsFlagSet( TRIPLE_PRESS_ALLOWED );
}

void Panel::InternalMouseTriplePressed( int code )
{
	Assert( IsTriplePressAllowed() );
	m_lLastDoublePressTime = 0L;

	if ( !ShouldHandleInputMessage() )
		return;

	if ( IsCursorNone() )
		return;
	
	if ( !IsMouseInputEnabled())
	{
#if defined( VGUI_USEDRAGDROP )
		DragDropStartDragging();
#endif
		return;
	}
	
	if (IsBuildGroupEnabled())
	{
		return;
	}

	OnMouseTriplePressed((MouseCode)code);
#if defined( VGUI_USEDRAGDROP )
	DragDropStartDragging();
#endif
}

void Panel::InternalMouseReleased(int code)
{
#if defined( VGUI_USEDRAGDROP )
	if ( g_DragDropCapture.Get() )
	{
		bool started = g_DragDropCapture->GetDragDropInfo()->m_bDragStarted;
		g_DragDropCapture->OnFinishDragging( true, (MouseCode)code );
		if ( started )
		{
			return;
		}
	}
#endif

	if ( !ShouldHandleInputMessage() )
		return;

	if ( IsCursorNone() )
		return;
	
	if ( !IsMouseInputEnabled())
	{
		return;
	}
	
	if (IsBuildGroupEnabled())
	{
		if ( _buildGroup->MouseReleased((MouseCode)code, this) )
		{
			return;
		}
	}

#ifdef STAGING_ONLY
	const char *pGameDir = CommandLine()->ParmValue( "-game", "hl2" );
	if ( tf_strict_mouse_up_events.GetBool() && !V_stricmp( pGameDir, "tf" ) )
	{
		// Only allow mouse release events to go to panels that we also
		// first clicked into
		if ( code >= MOUSE_LEFT && code <= MOUSE_MIDDLE )
		{
			const int nIndex = code - MOUSE_LEFT;
			Panel* pPressedPanel = m_sMousePressedPanels[ nIndex ];
			m_sMousePressedPanels[ nIndex ] = NULL;	// Clear out pressed panel
			if ( pPressedPanel != this )
			{
				OnMouseMismatchedRelease( (MouseCode)code, pPressedPanel );
				return;
			}
		}
	}
#endif

	OnMouseReleased((MouseCode)code);
}

void Panel::InternalMouseWheeled(int delta)
{
	if (IsBuildGroupEnabled() || !IsMouseInputEnabled())
	{
		return;
	}

	if ( !ShouldHandleInputMessage() )
		return;

	OnMouseWheeled(delta);
}

void Panel::InternalKeyCodePressed(int code)
{
	if ( !ShouldHandleInputMessage() )
		return;

	if (IsKeyBoardInputEnabled()) 
	{
		OnKeyCodePressed((KeyCode)code);
	}
	else
	{
		CallParentFunction(new KeyValues("KeyCodePressed", "code", code));
	}
}

#if defined( VGUI_USEKEYBINDINGMAPS )
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *bindingName - 
//			keycode - 
//			modifiers - 
//-----------------------------------------------------------------------------
void Panel::AddKeyBinding( char const *bindingName, int keycode, int modifiers )
{
	PanelKeyBindingMap *map = LookupMapForBinding( bindingName );
	if ( !map )
	{
		Assert( 0 );
		return;
	}		

	BoundKey_t kb;																	
	kb.isbuiltin = false;															
	kb.bindingname = CopyString( bindingName );												
	kb.keycode = keycode;															
	kb.modifiers = modifiers;														

	map->boundkeys.AddToTail( kb );													
}

KeyBindingMap_t *Panel::LookupBinding( char const *bindingName )
{
	PanelKeyBindingMap *map = GetKBMap();
	while( map )
	{
		int c = map->entries.Count();
		for( int i = 0; i < c ; ++i )
		{
			KeyBindingMap_t *binding = &map->entries[ i ];
			if ( !Q_stricmp( binding->bindingname, bindingName ) )
				return binding;
		}

		map = map->baseMap;
	}

	return NULL;
}

PanelKeyBindingMap *Panel::LookupMapForBinding( char const *bindingName )
{
	PanelKeyBindingMap *map = GetKBMap();
	while( map )
	{
		int c = map->entries.Count();
		for( int i = 0; i < c ; ++i )
		{
			KeyBindingMap_t *binding = &map->entries[ i ];
			if ( !Q_stricmp( binding->bindingname, bindingName ) )
				return map;
		}

		map = map->baseMap;
	}

	return NULL;
}

KeyBindingMap_t *Panel::LookupBindingByKeyCode( KeyCode code, int modifiers )
{
	PanelKeyBindingMap *map = GetKBMap();
	while( map )
	{
		int c = map->boundkeys.Count();
		for( int i = 0; i < c ; ++i )
		{
			BoundKey_t *kb = &map->boundkeys[ i ];
			if ( kb->keycode == code && kb->modifiers == modifiers )
			{
				KeyBindingMap_t *binding = LookupBinding( kb->bindingname );
				Assert( binding );
				if ( binding )
				{
					return binding;
				}
			}
		}

		map = map->baseMap;
	}

	return NULL;
}

BoundKey_t *Panel::LookupDefaultKey( char const *bindingName )
{
	PanelKeyBindingMap *map = GetKBMap();
	while( map )
	{
		int c = map->defaultkeys.Count();
		for( int i = 0; i < c ; ++i )
		{
			BoundKey_t *kb = &map->defaultkeys[ i ];
			if ( !Q_stricmp( kb->bindingname, bindingName ) )
			{
				return kb;
			}
		}

		map = map->baseMap;
	}
	return NULL;
}

void Panel::LookupBoundKeys( char const *bindingName, CUtlVector< BoundKey_t * >& list )
{
	PanelKeyBindingMap *map = GetKBMap();
	while( map )
	{
		int c = map->boundkeys.Count();
		for( int i = 0; i < c ; ++i )
		{
			BoundKey_t *kb = &map->boundkeys[ i ];
			if ( !Q_stricmp( kb->bindingname, bindingName ) )
			{
				list.AddToTail( kb );
			}
		}

		map = map->baseMap;
	}
}

void Panel::RevertKeyBindingsToDefault()
{
	PanelKeyBindingMap *map = GetKBMap();
	while( map )
	{
		map->boundkeys.RemoveAll();
		map->boundkeys = map->defaultkeys;

		map = map->baseMap;
	}
}

void Panel::RemoveAllKeyBindings()
{
	PanelKeyBindingMap *map = GetKBMap();
	while( map )
	{
		map->boundkeys.RemoveAll();
		map = map->baseMap;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
//-----------------------------------------------------------------------------
void Panel::ReloadKeyBindings()
{
	RevertKeyBindingsToDefault();
	LoadKeyBindingsForOnePanel( GetKeyBindingsContext(), this );
}

#define MAKE_STRING( x )	#x
#define KEY_NAME( str, disp )	{ KEY_##str, MAKE_STRING( KEY_##str ), disp }

struct KeyNames_t
{
	KeyCode		code;
	char const	*string;
	char const	*displaystring;
};

static KeyNames_t g_KeyNames[] =
{
KEY_NAME( NONE, "None" ),
KEY_NAME( 0, "0" ),
KEY_NAME( 1, "1" ),
KEY_NAME( 2, "2" ),
KEY_NAME( 3, "3" ),
KEY_NAME( 4, "4" ),
KEY_NAME( 5, "5" ),
KEY_NAME( 6, "6" ),
KEY_NAME( 7, "7" ),
KEY_NAME( 8, "8" ),
KEY_NAME( 9, "9" ),
KEY_NAME( A, "A" ),
KEY_NAME( B, "B" ),
KEY_NAME( C, "C" ),
KEY_NAME( D, "D" ),
KEY_NAME( E, "E" ),
KEY_NAME( F, "F" ),
KEY_NAME( G, "G" ),
KEY_NAME( H, "H" ),
KEY_NAME( I, "I" ),
KEY_NAME( J, "J" ),
KEY_NAME( K, "K" ),
KEY_NAME( L, "L" ),
KEY_NAME( M, "M" ),
KEY_NAME( N, "N" ),
KEY_NAME( O, "O" ),
KEY_NAME( P, "P" ),
KEY_NAME( Q, "Q" ),
KEY_NAME( R, "R" ),
KEY_NAME( S, "S" ),
KEY_NAME( T, "T" ),
KEY_NAME( U, "U" ),
KEY_NAME( V, "V" ),
KEY_NAME( W, "W" ),
KEY_NAME( X, "X" ),
KEY_NAME( Y, "Y" ),
KEY_NAME( Z, "Z" ),
KEY_NAME( PAD_0, "Key Pad 0" ),
KEY_NAME( PAD_1, "Key Pad 1" ),
KEY_NAME( PAD_2, "Key Pad 2" ),
KEY_NAME( PAD_3, "Key Pad 3" ),
KEY_NAME( PAD_4, "Key Pad 4" ),
KEY_NAME( PAD_5, "Key Pad 5" ),
KEY_NAME( PAD_6, "Key Pad 6" ),
KEY_NAME( PAD_7, "Key Pad 7" ),
KEY_NAME( PAD_8, "Key Pad 8" ),
KEY_NAME( PAD_9, "Key Pad 9" ),
KEY_NAME( PAD_DIVIDE, "Key Pad /" ),
KEY_NAME( PAD_MULTIPLY, "Key Pad *" ),
KEY_NAME( PAD_MINUS, "Key Pad -" ),
KEY_NAME( PAD_PLUS, "Key Pad +" ),
KEY_NAME( PAD_ENTER, "Key Pad Enter" ),
KEY_NAME( PAD_DECIMAL, "Key Pad ." ),
KEY_NAME( LBRACKET, "[" ),
KEY_NAME( RBRACKET, "]" ),
KEY_NAME( SEMICOLON, "," ),
KEY_NAME( APOSTROPHE, "'" ),
KEY_NAME( BACKQUOTE, "`" ),
KEY_NAME( COMMA, "," ),
KEY_NAME( PERIOD, "." ),
KEY_NAME( SLASH, "/" ),
KEY_NAME( BACKSLASH, "\\" ),
KEY_NAME( MINUS, "-" ),
KEY_NAME( EQUAL, "=" ),
KEY_NAME( ENTER, "Enter" ),
KEY_NAME( SPACE, "Space" ),
KEY_NAME( BACKSPACE, "Backspace" ),
KEY_NAME( TAB, "Tab" ),
KEY_NAME( CAPSLOCK, "Caps Lock" ),
KEY_NAME( NUMLOCK, "Num Lock" ),
KEY_NAME( ESCAPE, "Escape" ),
KEY_NAME( SCROLLLOCK, "Scroll Lock" ),
KEY_NAME( INSERT, "Ins" ),
KEY_NAME( DELETE, "Del" ),
KEY_NAME( HOME, "Home" ),
KEY_NAME( END, "End" ),
KEY_NAME( PAGEUP, "PgUp" ),
KEY_NAME( PAGEDOWN, "PgDn" ),
KEY_NAME( BREAK, "Break" ),
KEY_NAME( LSHIFT, "Shift" ),
KEY_NAME( RSHIFT, "Shift" ),
KEY_NAME( LALT, "Alt" ),
KEY_NAME( RALT, "Alt" ),
KEY_NAME( LCONTROL, "Ctrl" ),
KEY_NAME( RCONTROL, "Ctrl" ),
KEY_NAME( LWIN, "Windows" ),
KEY_NAME( RWIN, "Windows" ),
KEY_NAME( APP, "App" ),
KEY_NAME( UP, "Up" ),
KEY_NAME( LEFT, "Left" ),
KEY_NAME( DOWN, "Down" ),
KEY_NAME( RIGHT, "Right" ),
KEY_NAME( F1, "F1" ),
KEY_NAME( F2, "F2" ),
KEY_NAME( F3, "F3" ),
KEY_NAME( F4, "F4" ),
KEY_NAME( F5, "F5" ),
KEY_NAME( F6, "F6" ),
KEY_NAME( F7, "F7" ),
KEY_NAME( F8, "F8" ),
KEY_NAME( F9, "F9" ),
KEY_NAME( F10, "F10" ),
KEY_NAME( F11, "F11" ),
KEY_NAME( F12, "F12" ),
KEY_NAME( CAPSLOCKTOGGLE, "Caps Lock Toggle" ),
KEY_NAME( NUMLOCKTOGGLE, "Num Lock Toggle" ),
KEY_NAME( SCROLLLOCKTOGGLE, "Scroll Lock Toggle" ),
};

char const *Panel::KeyCodeToString( KeyCode code )
{
	int c = ARRAYSIZE( g_KeyNames );
	for ( int i = 0; i < c ; ++i )
	{
		if ( g_KeyNames[ i ].code == code )
			return g_KeyNames[ i ].string;
	}

	return "";
}

wchar_t const *Panel::KeyCodeToDisplayString( KeyCode code )
{
	int c = ARRAYSIZE( g_KeyNames );
	for ( int i = 0; i < c ; ++i )
	{
		if ( g_KeyNames[ i ].code == code )
		{
			char const *str = g_KeyNames[ i ].displaystring;
			wchar_t *wstr = g_pVGuiLocalize->Find( str );
			if ( wstr )
			{
				return wstr;
			}

			static wchar_t buf[ 64 ];
			g_pVGuiLocalize->ConvertANSIToUnicode( str, buf, sizeof( buf ) );
			return buf;
		}
	}

	return L"";
}

static void AddModifierToString( char const *modifiername, char *buf, size_t bufsize )
{
	char add[ 32 ];
	if ( Q_strlen( buf ) > 0 )
	{
		Q_snprintf( add, sizeof( add ), "+%s", modifiername );
	}
	else
	{
		Q_strncpy( add, modifiername, sizeof( add ) );
	}

	Q_strncat( buf, add, bufsize, COPY_ALL_CHARACTERS );
		
}

wchar_t const *Panel::KeyCodeModifiersToDisplayString( KeyCode code, int modifiers )
{
	char sz[ 256 ];
	sz[ 0 ] = 0;

	if ( modifiers & MODIFIER_SHIFT )
	{
		AddModifierToString( "Shift", sz, sizeof( sz ) );
	}
	if ( modifiers & MODIFIER_CONTROL )
	{
		AddModifierToString( "Ctrl", sz, sizeof( sz ) );
	}
	if ( modifiers & MODIFIER_ALT )
	{
		AddModifierToString( "Alt", sz, sizeof( sz ) );
	}

	if ( Q_strlen( sz ) > 0 )
	{
		Q_strncat( sz, "+", sizeof( sz ), COPY_ALL_CHARACTERS );
	}

	static wchar_t unicode[ 256 ];
	V_swprintf_safe( unicode, L"%S%s", sz, Panel::KeyCodeToDisplayString( (KeyCode)code ) );
	return unicode;
}

KeyCode Panel::StringToKeyCode( char const *str )
{
	int c = ARRAYSIZE( g_KeyNames );
	for ( int i = 0; i < c ; ++i )
	{
		if ( !Q_stricmp( str, g_KeyNames[ i ].string ) )
			return g_KeyNames[ i ].code;
	}

	return KEY_NONE;
}

static void WriteKeyBindingToBuffer( CUtlBuffer& buf, int level, const BoundKey_t& binding )
{
	BufPrint( buf, level, "\"keycode\"\t\"%s\"\n", Panel::KeyCodeToString( (KeyCode)binding.keycode ) );
	if ( binding.modifiers & MODIFIER_SHIFT )
	{
		BufPrint( buf, level, "\"shift\"\t\"1\"\n" );
	}
	if ( binding.modifiers & MODIFIER_CONTROL )
	{
		BufPrint( buf, level, "\"ctrl\"\t\"1\"\n" );
	}
	if ( binding.modifiers & MODIFIER_ALT )
	{
		BufPrint( buf, level, "\"alt\"\t\"1\"\n" );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *filename - 
//			*pathID - 
//-----------------------------------------------------------------------------
void Panel::SaveKeyBindingsToBuffer( int level, CUtlBuffer& buf  )
{
	Assert( IsValidKeyBindingsContext() );

	Assert( buf.IsText() );

	PanelKeyBindingMap *map = GetKBMap();
	while( map )
	{
		int c = map->boundkeys.Count();
		for( int i = 0; i < c ; ++i )
		{
			const BoundKey_t& binding = map->boundkeys[ i ];

			// Spew to file
			BufPrint( buf, level, "\"%s\"\n", binding.bindingname );
			BufPrint( buf, level, "{\n" );
	
			WriteKeyBindingToBuffer( buf, level + 1, binding );

			BufPrint( buf, level, "}\n" );
		}

		map = map->baseMap;
	}
}

bool Panel::ParseKeyBindings( KeyValues *kv )
{
	Assert( IsValidKeyBindingsContext() );
	if ( !IsValidKeyBindingsContext() )
		return false;

	// To have KB the panel must have a name
	Assert( GetName() && GetName()[ 0 ] );
	if ( !GetName() || !GetName()[ 0 ] )
		return false;

	bool success = false;

	g_KBMgr.AddPanelToContext( GetKeyBindingsContext(), this );

	RemoveAllKeyBindings();

	// Walk through bindings
	for ( KeyValues *binding = kv->GetFirstSubKey(); binding != NULL; binding = binding->GetNextKey() )
	{
		char const *bindingName = binding->GetName();
		if ( !bindingName || !bindingName[ 0 ] )
			continue;

		KeyBindingMap_t *b = LookupBinding( bindingName );
		if ( b )
		{
			success = true;
			const char *keycode = binding->GetString( "keycode", "" );
			int modifiers = 0;
			if ( binding->GetInt( "shift", 0 ) != 0 )
			{
				modifiers |= MODIFIER_SHIFT;
			}
			if ( binding->GetInt( "ctrl", 0 ) != 0 )
			{
				modifiers |= MODIFIER_CONTROL;
			}
			if ( binding->GetInt( "alt", 0 ) != 0 )
			{
				modifiers |= MODIFIER_ALT;
			}

			KeyBindingMap_t *bound = LookupBindingByKeyCode( StringToKeyCode( keycode ), modifiers );
			if ( !bound )
			{
				AddKeyBinding( bindingName, StringToKeyCode( keycode ), modifiers );
			}
		}
		else
		{
			Warning( "KeyBinding for panel '%s' contained unknown binding '%s'\n", GetName() ? GetName() : "???", bindingName );
		}
	}

	// Now for each binding which is currently "unbound" to any key, use the default binding
	PanelKeyBindingMap *map = GetKBMap();
	while( map )
	{
		int c = map->entries.Count();
		for( int i = 0; i < c ; ++i )
		{
			KeyBindingMap_t *binding = &map->entries[ i ];
			
			// See if there is a bound key
			CUtlVector< BoundKey_t * > list;
			LookupBoundKeys( binding->bindingname, list );
			if ( list.Count() == 0 )
			{
				// Assign the default binding to this key
				BoundKey_t *defaultKey = LookupDefaultKey( binding->bindingname );
				if ( defaultKey )
				{
					KeyBindingMap_t *alreadyBound = LookupBindingByKeyCode( (KeyCode)defaultKey->keycode, defaultKey->modifiers );
					if ( alreadyBound )
					{
						Warning( "No binding for '%s', defautl key already bound to '%s'\n", binding->bindingname, alreadyBound->bindingname );
					}
					else
					{
						AddKeyBinding( defaultKey->bindingname, defaultKey->keycode, defaultKey->modifiers );
					}
				}
			}
		}

		map = map->baseMap;
	}

	return success;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : handle - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
void Panel::SetKeyBindingsContext( KeyBindingContextHandle_t handle )
{
	Assert( !IsValidKeyBindingsContext() || handle == GetKeyBindingsContext() );
	g_KBMgr.AddPanelToContext( handle, this );
	m_hKeyBindingsContext = handle;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
// Output : KeyBindingContextHandle_t
//-----------------------------------------------------------------------------
KeyBindingContextHandle_t Panel::GetKeyBindingsContext() const
{
	return m_hKeyBindingsContext;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool Panel::IsValidKeyBindingsContext() const
{
	return GetKeyBindingsContext() != INVALID_KEYBINDINGCONTEXT_HANDLE;
}

char const *Panel::GetKeyBindingsFile() const
{
	Assert( IsValidKeyBindingsContext() );
	return g_KBMgr.GetKeyBindingsFile( GetKeyBindingsContext() );
}

char const *Panel::GetKeyBindingsFilePathID() const
{
	Assert( IsValidKeyBindingsContext() );
	return g_KBMgr.GetKeyBindingsFilePathID( GetKeyBindingsContext() );
}

void Panel::EditKeyBindings()
{
	Assert( 0 );
}


//-----------------------------------------------------------------------------
// Purpose: Set this to false to disallow IsKeyRebound chaining to GetParent() Panels...
// Input  : state - 
//-----------------------------------------------------------------------------
void Panel::SetAllowKeyBindingChainToParent( bool state )
{
	_flags.SetFlag( ALLOW_CHAIN_KEYBINDING_TO_PARENT, state );
}


//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool Panel::IsKeyBindingChainToParentAllowed() const
{
	return _flags.IsFlagSet( ALLOW_CHAIN_KEYBINDING_TO_PARENT );
}

bool Panel::IsKeyOverridden( KeyCode code, int modifiers )
{
	// By default assume all keys should pass through binding system
	return false;
}

bool Panel::IsKeyRebound( KeyCode code, int modifiers )
{
	if ( IsKeyBoardInputEnabled() )
	{ 
		KeyBindingMap_t* binding = LookupBindingByKeyCode( code, modifiers );
		// Only dispatch if we're part of the current modal subtree
		if ( binding && IsChildOfSurfaceModalPanel() )
		{
			// Found match, post message to panel
			if ( binding->func )
			{
				// dispatch the func
				(this->*binding->func)();
			}
			else
			{
				Assert( 0 );
			}

			if ( !binding->passive )
			{
				// Exit this function...
				return true;
			}
		}
	}

	// Chain to parent
	Panel* pParent = GetParent();
	if ( IsKeyBindingChainToParentAllowed() && pParent && !IsKeyOverridden( code, modifiers ) )
		return pParent->IsKeyRebound( code, modifiers );

	// No suitable binding found
	return false;
}

static bool s_bSuppressRebindChecks = false;
#endif // VGUI_USEKEYBINDINGMAPS

void Panel::InternalKeyCodeTyped( int code )
{
	if ( !ShouldHandleInputMessage() )
	{
		input()->OnKeyCodeUnhandled( code );
		return;
	}

	if (IsKeyBoardInputEnabled()) 
	{
		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));

		int modifiers = 0;
		if ( shift )
		{
			modifiers |= MODIFIER_SHIFT;
		}
		if ( ctrl )
		{
			modifiers |= MODIFIER_CONTROL;
		}
		if ( alt )
		{
			modifiers |= MODIFIER_ALT;
		}

		// Things in build mode don't have accelerators
		if (IsBuildGroupEnabled())
		{
			 _buildGroup->KeyCodeTyped((KeyCode)code, this);
			return;
		}

		if ( !s_bSuppressRebindChecks && IsKeyRebound( (KeyCode)code, modifiers ) )
		{
			return;
		}

		bool oldVal = s_bSuppressRebindChecks;
		s_bSuppressRebindChecks = true;
		OnKeyCodeTyped((KeyCode)code);
		s_bSuppressRebindChecks = oldVal;
	}
	else
	{
		if ( GetVPanel() == surface()->GetEmbeddedPanel() )
		{
			input()->OnKeyCodeUnhandled( code );
		}
		CallParentFunction(new KeyValues("KeyCodeTyped", "code", code));
	}
}

void Panel::InternalKeyTyped(int unichar)
{
	if ( !ShouldHandleInputMessage() )
		return;

	if (IsKeyBoardInputEnabled())
	{
		if ( IsBuildGroupEnabled() )
		{
			if ( _buildGroup->KeyTyped( (wchar_t)unichar, this ) )
			{
				return;
			}
		}

		OnKeyTyped((wchar_t)unichar);
	}
	else
	{
		CallParentFunction(new KeyValues("KeyTyped", "unichar", unichar));
	}
}

void Panel::InternalKeyCodeReleased(int code)
{
	if ( !ShouldHandleInputMessage() )
		return;

	if (IsKeyBoardInputEnabled()) 
	{
		if (IsBuildGroupEnabled())
		{
			if ( _buildGroup->KeyCodeReleased((KeyCode)code, this) )
			{
				return;
			}
		}

		OnKeyCodeReleased((KeyCode)code);
	}
	else
	{
		CallParentFunction(new KeyValues("KeyCodeReleased", "code", code));
	}
}

void Panel::InternalKeyFocusTicked()
{
	if (IsBuildGroupEnabled())
		return;
	
	OnKeyFocusTicked();
}

void Panel::InternalMouseFocusTicked()
{
	if (IsBuildGroupEnabled())
	{
		// must repaint so the numbers will be accurate
		if (_buildGroup->HasRulersOn())
		{
			PaintTraverse(true);
		}
		return;
	}

	// update cursor
	InternalSetCursor();
	OnMouseFocusTicked();
}


void Panel::InternalSetCursor()
{
	bool visible = IsVisible();

	if (visible)
	{
#if defined( VGUI_USEDRAGDROP )
		// Drag drop is overriding cursor?
		if ( m_pDragDrop->m_bDragging ||
			g_DragDropCapture.Get() != NULL )
			return;
#endif
		// chain up and make sure all our parents are also visible
		VPANEL p = GetVParent();
		while (p)
		{
			visible &= ipanel()->IsVisible(p);
			p = ipanel()->GetParent(p);
		}
	
		// only change the cursor if this panel is visible, and if its part of the main VGUI tree
		if (visible && HasParent(surface()->GetEmbeddedPanel())) 
		{	
			HCursor cursor = GetCursor();
			
			if (IsBuildGroupEnabled())
			{
				cursor = _buildGroup->GetCursor(this);
			}
			
			if (input()->GetCursorOveride())
			{
				cursor = input()->GetCursorOveride();
			}

			surface()->SetCursor(cursor);
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Called every frame the panel is visible, designed to be overridden
//-----------------------------------------------------------------------------
void Panel::OnThink()
{
#if defined( VGUI_USEDRAGDROP )
	if ( IsPC() && 
		m_pDragDrop->m_bDragEnabled &&
		m_pDragDrop->m_bDragging &&
		m_pDragDrop->m_bDragStarted )
	{
		bool isEscapeKeyDown = input()->IsKeyDown( KEY_ESCAPE );
		if ( isEscapeKeyDown )
		{
			OnContinueDragging();
			OnFinishDragging( true, (MouseCode)-1, true );
			return;
		}

		if ( m_pDragDrop->m_hCurrentDrop != 0 )
		{
			if ( !input()->IsMouseDown( MOUSE_LEFT ) )
			{
				OnContinueDragging();
				OnFinishDragging( true, (MouseCode)-1 );
				return;
			}

			// allow the cursor to change based upon things like changing keystate, etc.
			surface()->SetCursor( m_pDragDrop->m_hCurrentDrop->GetDropCursor( m_pDragDrop->m_DragData ) );

			if ( !m_pDragDrop->m_bDropMenuShown )
			{
				// See if the hover time has gotten larger
				float hoverSeconds = ( system()->GetTimeMillis() - m_pDragDrop->m_lDropHoverTime ) * 0.001f;
				DragDrop_t *dropInfo = m_pDragDrop->m_hCurrentDrop->GetDragDropInfo();

				if ( dropInfo->m_flHoverContextTime != 0.0f )
				{
					if ( hoverSeconds >= dropInfo->m_flHoverContextTime )
					{
						m_pDragDrop->m_bDropMenuShown = true;

						CUtlVector< KeyValues * > data;
						
						GetDragData( data );

						int x, y;
						input()->GetCursorPos( x, y );

						if ( m_pDragDrop->m_hDropContextMenu.Get() )
						{
							delete m_pDragDrop->m_hDropContextMenu.Get();
						}

						Menu *menu = new Menu( m_pDragDrop->m_hCurrentDrop.Get(), "DropContext" );
							
						bool useMenu = m_pDragDrop->m_hCurrentDrop->GetDropContextMenu( menu, data );
						if ( useMenu )
						{
							m_pDragDrop->m_hDropContextMenu = menu;

							menu->SetPos( x, y );
							menu->SetVisible( true );
							menu->MakePopup();
							surface()->MovePopupToFront( menu->GetVPanel() );
							if ( menu->GetItemCount() > 0 )
							{
								int id = menu->GetMenuID( 0 );
								menu->SetCurrentlyHighlightedItem( id );
								MenuItem *item = menu->GetMenuItem( id );
								item->SetArmed( true );
							}
						}
						else
						{
							delete menu;
						}

						m_pDragDrop->m_hCurrentDrop->OnDropContextHoverShow( data );
					}
				}
			}
		}
	}
#endif
}

// input messages handlers (designed for override)
void Panel::OnCursorMoved(int x, int y)
{
	if( ParentNeedsCursorMoveEvents() )
	{
		// figure out x and y in parent space
		int thisX, thisY;
		ipanel()->GetPos( GetVPanel(), thisX, thisY );
		CallParentFunction( new KeyValues( "OnCursorMoved", "x", x + thisX, "y", y + thisY ) );
	}
}

void Panel::OnCursorEntered()
{
}

void Panel::OnCursorExited()
{
}

void Panel::OnMousePressed(MouseCode code)
{
}

void Panel::OnMouseDoublePressed(MouseCode code)
{
}

void Panel::OnMouseTriplePressed(MouseCode code)
{
}

void Panel::OnMouseReleased(MouseCode code)
{
}

void Panel::OnMouseMismatchedRelease( MouseCode code, Panel* pPressedPanel )
{
}

void Panel::OnMouseWheeled(int delta)
{
	CallParentFunction(new KeyValues("MouseWheeled", "delta", delta));
}

// base implementation forwards Key messages to the Panel's parent - override to 'swallow' the input
void Panel::OnKeyCodePressed(KeyCode code)
{
	static ConVarRef vgui_nav_lock( "vgui_nav_lock" );

	bool handled = false;
	switch( GetBaseButtonCode( code ) )
	{
	case KEY_XBUTTON_UP:
	case KEY_XSTICK1_UP:
	case KEY_XSTICK2_UP:
	case KEY_UP:
	case STEAMCONTROLLER_DPAD_UP:
		if ( ( !vgui_nav_lock.IsValid() || vgui_nav_lock.GetInt() == 0 ) && NavigateUp() )
		{
			vgui_nav_lock.SetValue( 1 );
			vgui::surface()->PlaySound( "UI/menu_focus.wav" );
			handled = true;
		}
		break;
	case KEY_XBUTTON_DOWN:
	case KEY_XSTICK1_DOWN:
	case KEY_XSTICK2_DOWN:
	case KEY_DOWN:
	case STEAMCONTROLLER_DPAD_DOWN:
		if ( ( !vgui_nav_lock.IsValid() || vgui_nav_lock.GetInt() == 0 ) && NavigateDown() )
		{
			vgui_nav_lock.SetValue( 1 );
			vgui::surface()->PlaySound( "UI/menu_focus.wav" );
			handled = true;
		}
		break;
	case KEY_XBUTTON_LEFT:
	case KEY_XSTICK1_LEFT:
	case KEY_XSTICK2_LEFT:
	case KEY_LEFT:
	case STEAMCONTROLLER_DPAD_LEFT:
		if ( ( !vgui_nav_lock.IsValid() || vgui_nav_lock.GetInt() == 0 ) && NavigateLeft() )
		{
			vgui_nav_lock.SetValue( 1 );
			vgui::surface()->PlaySound( "UI/menu_focus.wav" );
			handled = true;
		}
		break;
	case KEY_XBUTTON_RIGHT:
	case KEY_XSTICK1_RIGHT:
	case KEY_XSTICK2_RIGHT:
	case KEY_RIGHT:
	case STEAMCONTROLLER_DPAD_RIGHT:
		if ( ( !vgui_nav_lock.IsValid() || vgui_nav_lock.GetInt() == 0 ) && NavigateRight() )
		{
			vgui_nav_lock.SetValue( 1 );
			vgui::surface()->PlaySound( "UI/menu_focus.wav" );
			handled = true;
		}
		break;
	case KEY_XBUTTON_B:
	case STEAMCONTROLLER_B:
		if ( ( !vgui_nav_lock.IsValid() || vgui_nav_lock.GetInt() == 0 ) && NavigateBack() )
		{
			vgui_nav_lock.SetValue( 1 );
			vgui::surface()->PlaySound( "UI/menu_focus.wav" );
			handled = true;
		}
		break;
	}

	if( !handled && !m_PassUnhandledInput )
		return;

	CallParentFunction(new KeyValues("KeyCodePressed", "code", code));
}

void Panel::OnKeyCodeTyped(KeyCode keycode)
{
	vgui::KeyCode code = GetBaseButtonCode( keycode );

	// handle focus change
	if ( IsX360() || IsConsoleStylePanel() )
	{
		// eat these typed codes, will get handled in OnKeyCodePressed
		switch ( code )
		{
		case KEY_XBUTTON_UP:
		case KEY_XSTICK1_UP:
		case KEY_XSTICK2_UP:
		case KEY_XBUTTON_DOWN:
		case KEY_XSTICK1_DOWN:
		case KEY_XSTICK2_DOWN:
		case KEY_XBUTTON_LEFT:
		case KEY_XSTICK1_LEFT:
		case KEY_XSTICK2_LEFT:
		case KEY_XBUTTON_RIGHT:
		case KEY_XSTICK1_RIGHT:
		case KEY_XSTICK2_RIGHT:
		case KEY_XBUTTON_A:
		case KEY_XBUTTON_B:
		case KEY_XBUTTON_X:
		case KEY_XBUTTON_Y:
		case KEY_XBUTTON_LEFT_SHOULDER:
		case KEY_XBUTTON_RIGHT_SHOULDER:
		case KEY_XBUTTON_BACK:
		case KEY_XBUTTON_START:
		case KEY_XBUTTON_STICK1:
		case KEY_XBUTTON_STICK2:
		case KEY_XBUTTON_LTRIGGER:
		case KEY_XBUTTON_RTRIGGER:
		case STEAMCONTROLLER_A:
		case STEAMCONTROLLER_B:

		case KEY_UP:
		case KEY_DOWN:
		case KEY_LEFT:
		case KEY_RIGHT:
		case STEAMCONTROLLER_DPAD_UP:
		case STEAMCONTROLLER_DPAD_DOWN:
		case STEAMCONTROLLER_DPAD_LEFT:
		case STEAMCONTROLLER_DPAD_RIGHT:
			return;
		}

		// legacy handling - need to re-enable for older apps?
		/*
		if ( code == KEY_XSTICK1_RIGHT || code == KEY_XBUTTON_RIGHT )
		{
		RequestFocusNext();
		return;
		}
		else if ( code == KEY_XSTICK1_LEFT || code == KEY_XBUTTON_LEFT )
		{
		RequestFocusPrev();
		return;
		}
		*/
	}

	if (code == KEY_TAB)
	{
		bool bShiftDown = input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT);

		if ( IsConsoleStylePanel() )
		{
			if ( bShiftDown )
			{
				NavigateUp();
			}
			else
			{
				NavigateDown();
			}
		}
		else
		{
			// if shift is down goto previous tab position, otherwise goto next
			if ( bShiftDown )
			{
				RequestFocusPrev();
			}
			else
			{
				RequestFocusNext();
			}
		}
	}
	else
	{
		// forward up
		if ( GetVPanel() == surface()->GetEmbeddedPanel() )
		{
			input()->OnKeyCodeUnhandled( keycode );
		}
		CallParentFunction(new KeyValues("KeyCodeTyped", "code", keycode));
	}
}

void Panel::OnKeyTyped(wchar_t unichar)
{
	CallParentFunction(new KeyValues("KeyTyped", "unichar", unichar));
}

void Panel::OnKeyCodeReleased(KeyCode code)
{
	CallParentFunction(new KeyValues("KeyCodeReleased", "code", code));
}

void Panel::OnKeyFocusTicked()
{
	CallParentFunction(new KeyValues("KeyFocusTicked"));
}

void Panel::OnMouseFocusTicked()
{
	CallParentFunction(new KeyValues("OnMouseFocusTicked"));
}

bool Panel::IsWithin(int x,int y)
{
	// check against our clip rect
	int clipRect[4];
	ipanel()->GetClipRect(GetVPanel(), clipRect[0], clipRect[1], clipRect[2], clipRect[3]);

	if (x < clipRect[0])
	{
		return false;
	}

	if (y < clipRect[1])
	{
		return false;
	}

	if (x >= clipRect[2])
	{
		return false;
	}

	if (y >= clipRect[3])
	{
		return false;
	}

	return true;
}

//-----------------------------------------------------------------------------
// Purpose: determines which is the topmost panel under the coordinates (x, y)
//-----------------------------------------------------------------------------
VPANEL Panel::IsWithinTraverse(int x, int y, bool traversePopups)
{
	// if this one is not visible, its children won't be either
	// also if it doesn't want mouse input its children can't get it either
	if (!IsVisible() || !IsMouseInputEnabled())
		return NULL;

	if (traversePopups)
	{
		// check popups first
		int i;
		CUtlVector< VPANEL > &children = ipanel()->GetChildren( GetVPanel() );
		int childCount = children.Count();
		for (i = childCount - 1; i >= 0; i--)
		{
			VPANEL panel = children[ i ];
			if (ipanel()->IsPopup(panel))
			{
				panel = ipanel()->IsWithinTraverse(panel, x, y, true);
				if (panel != null)
				{
					return panel;
				}
			}
		}

		// check children recursive, if you find one, just return first one
		// this checks in backwards order so the last child drawn for this panel is chosen which
		// coincides to how it would be visibly displayed
		for (i = childCount - 1; i >= 0; i--)
		{
			VPANEL panel = children[ i ];
			// we've already checked popups so ignore
			if (!ipanel()->IsPopup(panel))
			{
				panel = ipanel()->IsWithinTraverse(panel, x, y, true);
				if (panel != 0)
				{
					return panel;
				}
			}
		}

		// check ourself
		if ( !IsMouseInputDisabledForThisPanel() && IsWithin(x, y) )
		{
			return GetVPanel();
		}
	}
	else
	{
		// since we're not checking popups, it must be within us, so we can check ourself first
		if (IsWithin(x, y))
		{
			// check children recursive, if you find one, just return first one
			// this checks in backwards order so the last child drawn for this panel is chosen which
			// coincides to how it would be visibly displayed
			CUtlVector< VPANEL > &children = ipanel()->GetChildren( GetVPanel() );
			int childCount = children.Count();
			for (int i = childCount - 1; i >= 0; i--)
			{
				VPANEL panel = children[ i ];
				// ignore popups
				if (!ipanel()->IsPopup(panel))
				{
					panel = ipanel()->IsWithinTraverse(panel, x, y, false);
					if (panel != 0)
					{
						return panel;
					}
				}
			}

			// not a child, must be us
			if ( !IsMouseInputDisabledForThisPanel() )
				return GetVPanel();
		}
	}

	return NULL;
}

void Panel::LocalToScreen(int& x,int& y)
{
	int px, py;
	ipanel()->GetAbsPos(GetVPanel(), px, py);

	x = x + px;
	y = y + py;
}

void Panel::ScreenToLocal(int& x,int& y)
{
	int px, py;
	ipanel()->GetAbsPos(GetVPanel(), px, py);

	x = x - px;
	y = y - py;
}

void Panel::ParentLocalToScreen(int &x, int &y)
{
	int px, py;
	ipanel()->GetAbsPos(GetVParent(), px, py);

	x = x + px;
	y = y + py;
}

void Panel::MakePopup(bool showTaskbarIcon,bool disabled)
{
	surface()->CreatePopup(GetVPanel(), false, showTaskbarIcon,disabled);
}

void Panel::SetCursor(HCursor cursor)
{
	_cursor = cursor;
}

HCursor Panel::GetCursor()
{
	return _cursor;
}

void Panel::SetCursorAlwaysVisible( bool visible )
{
	surface()->SetCursorAlwaysVisible( visible );
}

void Panel::SetMinimumSize(int wide,int tall)
{
	ipanel()->SetMinimumSize(GetVPanel(), wide, tall);
}

void Panel::GetMinimumSize(int& wide,int &tall)
{
	ipanel()->GetMinimumSize(GetVPanel(), wide, tall);
}

bool Panel::IsBuildModeEditable()
{
	return true;
}

void Panel::SetBuildModeEditable(bool state)
{
	if (state)
	{
		_buildModeFlags |= BUILDMODE_EDITABLE;
	}
	else
	{
		_buildModeFlags &= ~BUILDMODE_EDITABLE;
	}
}

//-----------------------------------------------------------------------------
// Purpose: data accessor
//-----------------------------------------------------------------------------
bool Panel::IsBuildModeDeletable()
{
	return (_buildModeFlags & BUILDMODE_DELETABLE);
}

//-----------------------------------------------------------------------------
// Purpose: data accessor
//-----------------------------------------------------------------------------
void Panel::SetBuildModeDeletable(bool state)
{
	if (state)
	{
		_buildModeFlags |= BUILDMODE_DELETABLE;
	}
	else
	{
		_buildModeFlags &= ~BUILDMODE_DELETABLE;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool Panel::IsBuildModeActive()
{
	return _buildGroup ? _buildGroup->IsEnabled() : false;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::GetClipRect(int& x0,int& y0,int& x1,int& y1)
{
	ipanel()->GetClipRect(GetVPanel(), x0, y0, x1, y1);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int Panel::GetChildCount()
{
    if (ipanel())
    {
	    return ipanel()->GetChildCount(GetVPanel());
    }

    return 0;
}

//-----------------------------------------------------------------------------
// Purpose: returns a child by the specified index
//-----------------------------------------------------------------------------
Panel *Panel::GetChild(int index)
{
	// get the child and cast it to a panel
	// this assumes that the child is from the same module as the this (precondition)
	return ipanel()->GetPanel(ipanel()->GetChild(GetVPanel(), index), GetControlsModuleName());
}

CUtlVector< VPANEL > &Panel::GetChildren()
{
	return ipanel()->GetChildren(GetVPanel());
}

//-----------------------------------------------------------------------------
// Purpose: moves the key focus back
//-----------------------------------------------------------------------------
bool Panel::RequestFocusPrev(VPANEL panel)
{
	// chain to parent
	if (GetVParent())
	{
		return ipanel()->RequestFocusPrev(GetVParent(), GetVPanel());
	}
	return false;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool Panel::RequestFocusNext(VPANEL panel)
{
	// chain to parent
	if (GetVParent())
	{
		return ipanel()->RequestFocusNext(GetVParent(), GetVPanel());
	}
	return false;
}

//-----------------------------------------------------------------------------
// Purpose: Sets the panel to have the current sub focus
// Input  : direction - the direction in which focus travelled to arrive at this panel; forward = 1, back = -1
//-----------------------------------------------------------------------------
void Panel::RequestFocus(int direction)
{
	// NOTE: This doesn't make any sense if we don't have keyboard input enabled
	// NOTE: Well, maybe it does if you have a steam controller...
	// Assert( ( IsX360() || IsConsoleStylePanel() ) || IsKeyBoardInputEnabled() );
	//	ivgui()->DPrintf2("RequestFocus(%s, %s)\n", GetName(), GetClassName());
	OnRequestFocus(GetVPanel(), NULL);
}

//-----------------------------------------------------------------------------
// Purpose: Called after a panel requests focus to fix up the whole chain
//-----------------------------------------------------------------------------
void Panel::OnRequestFocus(VPANEL subFocus, VPANEL defaultPanel)
{
	CallParentFunction(new KeyValues("OnRequestFocus", "subFocus", ivgui()->PanelToHandle( subFocus ), "defaultPanel", ivgui()->PanelToHandle( defaultPanel )));
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
VPANEL Panel::GetCurrentKeyFocus()
{
	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose: returns true if the panel has focus
//-----------------------------------------------------------------------------
bool Panel::HasFocus()
{
	if (input()->GetFocus() == GetVPanel())
	{
		return true;
	}
	return false;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::SetTabPosition(int position)
{
	_tabPosition = position;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int Panel::GetTabPosition()
{
	return _tabPosition;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::InternalFocusChanged(bool lost)
{
	/*
	//if focus is gained tell the focusNavGroup about it so its current can be correct
	if( (!lost) && (_focusNavGroup!=null) )
	{
	_focusNavGroup->setCurrentPanel(this);
	}
	*/
}

//-----------------------------------------------------------------------------
// Purpose: Called when a panel loses it's mouse capture
//-----------------------------------------------------------------------------
void Panel::OnMouseCaptureLost()
{
	if (m_pTooltips)
	{
		m_pTooltips->ResetDelay();
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::AddActionSignalTarget(Panel *messageTarget)
{
	HPanel target = ivgui()->PanelToHandle(messageTarget->GetVPanel());
	if (!_actionSignalTargetDar.HasElement(target))
	{
		_actionSignalTargetDar.AddElement(target);
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::AddActionSignalTarget(VPANEL messageTarget)
{
	HPanel target = ivgui()->PanelToHandle(messageTarget);
	if (!_actionSignalTargetDar.HasElement(target))
	{
		_actionSignalTargetDar.AddElement(target);
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::RemoveActionSignalTarget(Panel *oldTarget)
{
	_actionSignalTargetDar.RemoveElement(ivgui()->PanelToHandle(oldTarget->GetVPanel()));
}

//-----------------------------------------------------------------------------
// Purpose: Sends a message to all the panels that have requested action signals
//-----------------------------------------------------------------------------
void Panel::PostActionSignal( KeyValues *message )
{
	if ( m_bIsSilent != true )
	{	
		// add who it was from the message
		message->SetPtr("panel", this);
		int i;
		for (i = _actionSignalTargetDar.GetCount() - 1; i > 0; i--)
		{
			VPANEL panel = ivgui()->HandleToPanel(_actionSignalTargetDar[i]);
			if (panel)
			{
				ivgui()->PostMessage(panel, message->MakeCopy(), GetVPanel());
			}
		}

		// do this so we can save on one MakeCopy() call
		if (i == 0)
		{
			VPANEL panel = ivgui()->HandleToPanel(_actionSignalTargetDar[i]);
			if (panel)
			{
				ivgui()->PostMessage(panel, message, GetVPanel());
				return;
			}
		}
	}
	message->deleteThis();
}

void Panel::SetBorder(IBorder *border)
{
	tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s", __FUNCTION__, GetName() );
	_border = border;

	if (border)
	{
		int x, y, x2, y2;
		border->GetInset(x, y, x2, y2);
		ipanel()->SetInset(GetVPanel(), x, y, x2, y2);

		// update our background type based on the bord
		SetPaintBackgroundType(border->GetBackgroundType());
	}
	else
	{
		ipanel()->SetInset(GetVPanel(), 0, 0, 0, 0);
	}
}

IBorder *Panel::GetBorder()
{
	return _border;
}


void Panel::SetPaintBorderEnabled(bool state)
{
	_flags.SetFlag( PAINT_BORDER_ENABLED, state );
}

void Panel::SetPaintBackgroundEnabled(bool state)
{
	_flags.SetFlag( PAINT_BACKGROUND_ENABLED, state );
}

void Panel::SetPaintBackgroundType( int type )
{
	// HACK only 0 through 2 supported for now
	m_nPaintBackgroundType = clamp( type, 0, 2 );
}

void Panel::SetPaintEnabled(bool state)
{
	_flags.SetFlag( PAINT_ENABLED, state );
}

void Panel::SetPostChildPaintEnabled(bool state)
{
	_flags.SetFlag( POST_CHILD_PAINT_ENABLED, state );
}

void Panel::GetInset(int& left,int& top,int& right,int& bottom)
{
	ipanel()->GetInset(GetVPanel(), left, top, right, bottom);
}

void Panel::GetPaintSize(int& wide,int& tall)
{
	GetSize(wide, tall);
	if (_border != null)
	{
		int left,top,right,bottom;
		_border->GetInset(left,top,right,bottom);

		wide -= (left+right);
		tall -= (top+bottom);
	}
}

int Panel::GetWide()
{
	int wide, tall;
	ipanel()->GetSize(GetVPanel(), wide, tall);
	return wide;
}

void Panel::SetWide(int wide)
{
	ipanel()->SetSize(GetVPanel(), wide, GetTall());
}

int Panel::GetTall()
{
	int wide, tall;
	ipanel()->GetSize(GetVPanel(), wide, tall);
	return tall;
}

void Panel::SetTall(int tall)
{
	ipanel()->SetSize(GetVPanel(), GetWide(), tall);
}

void Panel::SetBuildGroup(BuildGroup* buildGroup)
{
	//TODO: remove from old group

        Assert(buildGroup != NULL);
        _buildGroup = buildGroup;
        _buildGroup->PanelAdded(this);
}

bool Panel::IsBuildGroupEnabled()
{
	if ( !_buildGroup.IsValid() )
		return false;

	bool enabled = _buildGroup->IsEnabled();
	if ( enabled )
		return enabled;

	if ( GetParent() && GetParent()->IsBuildGroupEnabled() )
		return true;

	return false;
}

void Panel::SetBgColor(Color color)
{
	_bgColor = color;
}

void Panel::SetFgColor(Color color)
{
	_fgColor = color;
}

Color Panel::GetBgColor()
{
	return _bgColor;
}

Color Panel::GetFgColor()
{
	return _fgColor;
}

void Panel::InternalPerformLayout()
{
	// Don't layout if we're still waiting for our scheme to be applied.
	// At worst, it leads to crashes, at best it does work that we'll redo as soon as the scheme has been applied.
	if ( _flags.IsFlagSet( NEEDS_SCHEME_UPDATE ) )
		return;

	_flags.SetFlag( IN_PERFORM_LAYOUT );
	// make sure the scheme has been applied
	_flags.ClearFlag( NEEDS_LAYOUT );
	PerformLayout();
	_flags.ClearFlag( IN_PERFORM_LAYOUT );
}

void Panel::PerformLayout()
{
	// this should be overridden to relayout controls
}

void Panel::InvalidateLayout( bool layoutNow, bool reloadScheme )
{
	_flags.SetFlag( NEEDS_LAYOUT );
	
	if (reloadScheme)
	{
		// make all our children reload the scheme
		_flags.SetFlag( NEEDS_SCHEME_UPDATE );
	
		for (int i = 0; i < GetChildCount(); i++)
		{
			vgui::Panel* panel = GetChild(i);
			if( panel )
			{
				panel->InvalidateLayout(layoutNow, true);
			}
		}
		
		PerformApplySchemeSettings();
	}
	
	if (layoutNow)
	{
		InternalPerformLayout();
		Repaint();
	}
}

bool Panel::IsCursorNone()
{
	HCursor cursor = GetCursor();

	if (!cursor)
	{
		return true;
	}
	
	return false;
}

//-----------------------------------------------------------------------------
// Purpose: returns true if the cursor is currently over the panel
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool Panel::IsCursorOver(void)
{
	int x, y;
	input()->GetCursorPos(x, y);
	return IsWithin(x, y);
}

//-----------------------------------------------------------------------------
// Purpose: Called when a panel receives a command message from another panel
//-----------------------------------------------------------------------------
void Panel::OnCommand(const char *command)
{
	if ( !Q_stricmp( "performlayout", command ) )
	{
		InvalidateLayout();
	}
	else if ( !Q_stricmp( "reloadscheme", command ) )
	{
		InvalidateLayout( false, true );
	}
	else
	{
		// if noone else caught this, pass along to the listeners
		// (this is useful for generic dialogs - otherwise, commands just get ignored)
		KeyValues *msg = new KeyValues( command );
		PostActionSignal( msg );
	}
}

//-----------------------------------------------------------------------------
// Purpose: panel gained focus message
//-----------------------------------------------------------------------------
void Panel::OnSetFocus()
{
	Repaint();
}

//-----------------------------------------------------------------------------
// Purpose: panel lost focus message
//-----------------------------------------------------------------------------
void Panel::OnKillFocus()
{
	Repaint();
}

//-----------------------------------------------------------------------------
// Purpose: Sets the object up to be deleted next frame
//-----------------------------------------------------------------------------
void Panel::MarkForDeletion()
{
	if ( _flags.IsFlagSet( MARKED_FOR_DELETION ) )
		return;

	_flags.SetFlag( MARKED_FOR_DELETION );
	_flags.ClearFlag( AUTODELETE_ENABLED );

	if (ivgui()->IsRunning())
	{
		ivgui()->MarkPanelForDeletion(GetVPanel());
	}
	// direct delete is never safe because even if ivgui is shutdown we manually do RunFrame()
	// and we can enter here in a think traverse and then delete from underneath ourselves
	/*else
	{
		delete this;
	}*/
}

//-----------------------------------------------------------------------------
// Purpose: return true if this object require a perform layout
//-----------------------------------------------------------------------------
bool Panel::IsLayoutInvalid()
{
	return _flags.IsFlagSet( NEEDS_LAYOUT );
}


//-----------------------------------------------------------------------------
// Sets the pin corner + resize mode for resizing panels
//-----------------------------------------------------------------------------
void Panel::SetAutoResize( PinCorner_e pinCorner, AutoResize_e resizeDir, 
						   int nPinOffsetX, int nPinOffsetY, int nUnpinnedCornerOffsetX, int nUnpinnedCornerOffsetY )
{
	_pinCorner = pinCorner;
	_autoResizeDirection = resizeDir;
	m_nPinDeltaX = nPinOffsetX;
	m_nPinDeltaY = nPinOffsetY;
	m_nResizeDeltaX = nUnpinnedCornerOffsetX;
	m_nResizeDeltaY = nUnpinnedCornerOffsetY;
}


//-----------------------------------------------------------------------------
// Sets the pin corner for non-resizing panels
//-----------------------------------------------------------------------------
void Panel::SetPinCorner( PinCorner_e pinCorner, int nOffsetX, int nOffsetY )
{
	_pinCorner = pinCorner;
	_autoResizeDirection = AUTORESIZE_NO;
	m_nPinDeltaX = nOffsetX;
	m_nPinDeltaY = nOffsetY;
	m_nResizeDeltaX = 0;
	m_nResizeDeltaY = 0;
}

	
//-----------------------------------------------------------------------------
// Purpose: data accessor
//-----------------------------------------------------------------------------
Panel::PinCorner_e Panel::GetPinCorner()
{
	return (PinCorner_e)_pinCorner;
}


//-----------------------------------------------------------------------------
// Gets the relative offset of the control from the pin corner
//-----------------------------------------------------------------------------
void Panel::GetPinOffset( int &dx, int &dy )
{
	dx = m_nPinDeltaX;
	dy = m_nPinDeltaY;
}


//-----------------------------------------------------------------------------
// Purpose: data accessor
//-----------------------------------------------------------------------------
Panel::AutoResize_e Panel::GetAutoResize()
{
	return (AutoResize_e)_autoResizeDirection;
}


//-----------------------------------------------------------------------------
// Gets the relative offset of the control from the pin corner
//-----------------------------------------------------------------------------
void Panel::GetResizeOffset( int &dx, int &dy )
{
	dx = m_nResizeDeltaX;
	dy = m_nResizeDeltaY;
}

//-----------------------------------------------------------------------------
// Tells this panel that it should pin itself to the corner of a specified sibling panel
//-----------------------------------------------------------------------------
void Panel::PinToSibling( const char *pszSibling, PinCorner_e pinOurCorner, PinCorner_e pinSibling )
{
	_pinCornerToSibling = pinOurCorner;
	_pinToSiblingCorner = pinSibling;

	if ( m_pinSibling.Get() && _pinToSibling && pszSibling && !Q_strcmp( _pinToSibling, pszSibling ) )
		return;

	if (_pinToSibling)
	{
		delete [] _pinToSibling;
		_pinToSibling = NULL;
	}

	if (pszSibling)
	{
		int len = Q_strlen(pszSibling) + 1;
		_pinToSibling = new char[ len ];
		Q_strncpy( _pinToSibling, pszSibling, len );
	}
	m_pinSibling = NULL;

	UpdateSiblingPin();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::UpdateSiblingPin( void )
{
	if ( !_pinToSibling )
	{
		ipanel()->SetSiblingPin(GetVPanel(), NULL);
		return;
	}

	if ( !m_pinSibling.Get() )
	{
		// Resolve our sibling now
		m_pinSibling = FindSiblingByName( _pinToSibling );
	}

	if ( m_pinSibling.Get() )
	{
		ipanel()->SetSiblingPin( GetVPanel(), m_pinSibling->GetVPanel(), _pinCornerToSibling, _pinToSiblingCorner );
	}
	else
	{
		ipanel()->SetSiblingPin(GetVPanel(), NULL);
	}
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::ApplySchemeSettings(IScheme *pScheme)
{
	// get colors
	SetFgColor(GetSchemeColor("Panel.FgColor", pScheme));
	SetBgColor(GetSchemeColor("Panel.BgColor", pScheme));

#if defined( VGUI_USEDRAGDROP )
	m_clrDragFrame = pScheme->GetColor("DragDrop.DragFrame", Color(255, 255, 255, 192));
	m_clrDropFrame = pScheme->GetColor("DragDrop.DropFrame", Color(150, 255, 150, 255));

	m_infoFont = pScheme->GetFont( "DefaultVerySmall" );
#endif
	// mark us as no longer needing scheme settings applied
	_flags.ClearFlag( NEEDS_SCHEME_UPDATE );

	if ( IsBuildGroupEnabled() )
	{
		_buildGroup->ApplySchemeSettings(pScheme);
		return;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Checks to see if the panel needs it's scheme info setup
//-----------------------------------------------------------------------------
void Panel::PerformApplySchemeSettings()
{
	if ( _flags.IsFlagSet( NEEDS_DEFAULT_SETTINGS_APPLIED ) )
	{
		InternalInitDefaultValues( GetAnimMap() );
	}

	if ( _flags.IsFlagSet( NEEDS_SCHEME_UPDATE ) )
	{
		VPROF( "ApplySchemeSettings" );
		IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
		AssertOnce( pScheme );
		if ( pScheme ) // this should NEVER be null, but if it is bad things would happen in ApplySchemeSettings...
		{
			ApplySchemeSettings( pScheme );
			//_needsSchemeUpdate = false;	

			ApplyOverridableColors();

			UpdateSiblingPin();
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Loads panel details related to autoresize from the resource info
//-----------------------------------------------------------------------------
#if defined( _DEBUG )
static Panel *lastWarningParent = 0;
#endif

void Panel::ApplyAutoResizeSettings(KeyValues *inResourceData)
{
	tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s", __FUNCTION__, GetName() );

	int x, y;
	GetPos(x, y);

	int wide, tall;
	GetSize( wide, tall );

	AutoResize_e autoResize = (AutoResize_e)inResourceData->GetInt( "AutoResize", AUTORESIZE_NO );
	PinCorner_e pinCorner = (PinCorner_e)inResourceData->GetInt( "PinCorner", PIN_TOPLEFT );

	// By default, measure unpinned corner for the offset
	int pw = wide, pt = tall;
	if ( GetParent() )
	{
		GetParent()->GetSize( pw, pt );
#if defined( _DEBUG )
		if ( pw == 64 && pt == 24 )
		{
			if ( GetParent() != lastWarningParent )
			{
				lastWarningParent = GetParent();
				Warning( "Resize parent (panel(%s) -> parent(%s)) not sized yet!!!\n", GetName(), GetParent()->GetName() );
			}
		}
#endif
	}

	int nPinnedCornerOffsetX = 0, nPinnedCornerOffsetY = 0;
	int nUnpinnedCornerOffsetX = 0, nUnpinnedCornerOffsetY = 0;
	switch( pinCorner )
	{
	case PIN_TOPLEFT:
		nPinnedCornerOffsetX = x;
		nPinnedCornerOffsetY = y;
		nUnpinnedCornerOffsetX = (x + wide) - pw;
		nUnpinnedCornerOffsetY = (y + tall) - pt;
		break;

	case PIN_TOPRIGHT:
		nPinnedCornerOffsetX = (x + wide) - pw;
		nPinnedCornerOffsetY = y;
		nUnpinnedCornerOffsetX = x;
		nUnpinnedCornerOffsetY = (y + tall) - pt;
		break;

	case PIN_BOTTOMLEFT:
		nPinnedCornerOffsetX = x;
		nPinnedCornerOffsetY = (y + tall) - pt;
		nUnpinnedCornerOffsetX = (x + wide) - pw;
		nUnpinnedCornerOffsetY = y;
		break;

	case PIN_BOTTOMRIGHT:
		nPinnedCornerOffsetX = (x + wide) - pw;
		nPinnedCornerOffsetY = (y + tall) - pt;
		nUnpinnedCornerOffsetX = x;
		nUnpinnedCornerOffsetY = y;
		break;
	}

	// Allow specific overrides in the resource file
	if ( IsProportional() )
	{
		if ( inResourceData->FindKey( "PinnedCornerOffsetX" ) )
		{
			nPinnedCornerOffsetX = scheme()->GetProportionalScaledValueEx( GetScheme(), inResourceData->GetInt( "PinnedCornerOffsetX" ) );
		}
		if ( inResourceData->FindKey( "PinnedCornerOffsetY" ) )
		{
			nPinnedCornerOffsetY =	scheme()->GetProportionalScaledValueEx( GetScheme(), inResourceData->GetInt( "PinnedCornerOffsetY" ) );
		}
		if ( inResourceData->FindKey( "UnpinnedCornerOffsetX" ) )
		{
			nUnpinnedCornerOffsetX = scheme()->GetProportionalScaledValueEx( GetScheme(), inResourceData->GetInt( "UnpinnedCornerOffsetX" ) );
		}
		if ( inResourceData->FindKey( "UnpinnedCornerOffsetY" ) )
		{
			nUnpinnedCornerOffsetY = scheme()->GetProportionalScaledValueEx( GetScheme(), inResourceData->GetInt( "UnpinnedCornerOffsetY" ) );
		}
	}
	else
	{
		nPinnedCornerOffsetX = inResourceData->GetInt( "PinnedCornerOffsetX", nPinnedCornerOffsetX );
		nPinnedCornerOffsetY = inResourceData->GetInt( "PinnedCornerOffsetY", nPinnedCornerOffsetY );
		nUnpinnedCornerOffsetX = inResourceData->GetInt( "UnpinnedCornerOffsetX", nUnpinnedCornerOffsetX );
		nUnpinnedCornerOffsetY = inResourceData->GetInt( "UnpinnedCornerOffsetY", nUnpinnedCornerOffsetY );
	}

	if ( autoResize == AUTORESIZE_NO )
	{
		nUnpinnedCornerOffsetX = nUnpinnedCornerOffsetY = 0;
	}

	SetAutoResize( pinCorner, autoResize, nPinnedCornerOffsetX, nPinnedCornerOffsetY, nUnpinnedCornerOffsetX, nUnpinnedCornerOffsetY );
}

ConVar panel_test_title_safe( "panel_test_title_safe", "0", FCVAR_CHEAT, "Test vgui panel positioning with title safe indentation" );





Panel::PinCorner_e GetPinCornerFromString( const char* pszCornerName )
{
	if ( pszCornerName == NULL )
	{
		return Panel::PIN_TOPLEFT;
	}

	// Optimize for all the old entries of a single digit
	if ( strlen( pszCornerName ) == 1 )
	{
		return (Panel::PinCorner_e)atoi( pszCornerName );
	}

	for( int i=0; i<ARRAYSIZE( g_PinCornerStrings ); ++i )
	{
		if ( !Q_stricmp( g_PinCornerStrings[i], pszCornerName ) )
		{
			return (Panel::PinCorner_e)i;
		}
	}

	return Panel::PIN_TOPLEFT;
}

//-----------------------------------------------------------------------------
// Purpose: Loads panel details from the resource info
//-----------------------------------------------------------------------------
void Panel::ApplySettings(KeyValues *inResourceData)
{
	tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s", __FUNCTION__, GetName() );

	// First restore to default values
	if ( _flags.IsFlagSet( NEEDS_DEFAULT_SETTINGS_APPLIED ) )
	{
		InternalInitDefaultValues( GetAnimMap() );
	}

	// Let PanelAnimationVars auto-retrieve settings (we restore defaults above
	//  since a script might be missing certain values)
	InternalApplySettings( GetAnimMap(), inResourceData );

	// clear any alignment flags
	_buildModeFlags &= ~( BUILDMODE_SAVE_XPOS_RIGHTALIGNED
						| BUILDMODE_SAVE_XPOS_CENTERALIGNED
						| BUILDMODE_SAVE_YPOS_BOTTOMALIGNED
						| BUILDMODE_SAVE_YPOS_CENTERALIGNED
						| BUILDMODE_SAVE_WIDE_FULL
						| BUILDMODE_SAVE_TALL_FULL
						| BUILDMODE_SAVE_PROPORTIONAL_TO_PARENT
						| BUILDMODE_SAVE_WIDE_PROPORTIONAL
						| BUILDMODE_SAVE_TALL_PROPORTIONAL
						| BUILDMODE_SAVE_XPOS_PROPORTIONAL_SELF
						| BUILDMODE_SAVE_YPOS_PROPORTIONAL_SELF
						| BUILDMODE_SAVE_WIDE_PROPORTIONAL_TALL
						| BUILDMODE_SAVE_TALL_PROPORTIONAL_WIDE
						| BUILDMODE_SAVE_XPOS_PROPORTIONAL_PARENT
						| BUILDMODE_SAVE_YPOS_PROPORTIONAL_PARENT
						| BUILDMODE_SAVE_WIDE_PROPORTIONAL_SELF
						| BUILDMODE_SAVE_TALL_PROPORTIONAL_SELF );

	// get the position
	int alignScreenWide, alignScreenTall;	// screen dimensions used for pinning in splitscreen
	surface()->GetScreenSize( alignScreenWide, alignScreenTall );

	int screenWide = alignScreenWide;
	int screenTall = alignScreenTall;

	// temporarily remove the override to get the fullscreen dimensions
	if ( surface()->IsScreenSizeOverrideActive() )
	{
		surface()->ForceScreenSizeOverride( false, 0, 0 );
		surface()->GetScreenSize( screenWide, screenTall );

		// restore the override
		surface()->ForceScreenSizeOverride( true, alignScreenWide, alignScreenTall );
	}

	int parentX = 0;
	int parentY = 0;

	// flag to cause windows to get screenWide and screenTall from their parents,
	// this allows children windows to use fill and right/bottom alignment even
	// if their parent does not use the full screen.
	if ( inResourceData->GetInt( "proportionalToParent", 0 ) == 1 )
	{
		_buildModeFlags |= BUILDMODE_SAVE_PROPORTIONAL_TO_PARENT;
		if ( GetParent() != NULL )
		{
			GetParent()->GetBounds( parentX, parentY, alignScreenWide, alignScreenTall );
		}
	}

	// size
	int wide = ComputeWide( this, _buildModeFlags, inResourceData, alignScreenWide, alignScreenTall, false );
	int tall = ComputeTall( this, _buildModeFlags, inResourceData, alignScreenWide, alignScreenTall, false );

	int x, y;
	GetPos(x, y);
	const char *xstr = inResourceData->GetString( "xpos", NULL );
	const char *ystr = inResourceData->GetString( "ypos", NULL );
	_buildModeFlags |= ComputePos( this, xstr, x, wide, alignScreenWide, true, OP_SET );
	_buildModeFlags |= ComputePos( this, ystr, y, tall, alignScreenTall, false, OP_SET );
	

	bool bUsesTitleSafeArea = false;
	int titleSafeWide = 0;
	int titleSafeTall = 0;

	Rect_t excludeEdgeFromTitleSafe;	// if a side is set to != 0, don't title safe relative to that edge
	excludeEdgeFromTitleSafe.x = 0;
	excludeEdgeFromTitleSafe.y = 0;
	excludeEdgeFromTitleSafe.width = 0;
	excludeEdgeFromTitleSafe.height = 0;

	if ( IsX360() || panel_test_title_safe.GetBool() )
	{
		// "usetitlesafe" "1" - required inner 90%
		// "usetitlesafe" "2" - suggested inner 85%

		int iUseTitleSafeValue = 0;
		if ( inResourceData->FindKey( "usetitlesafe" ) )
		{
			iUseTitleSafeValue = inResourceData->GetInt( "usetitlesafe" );
			bUsesTitleSafeArea = ( iUseTitleSafeValue > 0 );
		}

		if( bUsesTitleSafeArea )
		{
			titleSafeWide = screenWide * ( iUseTitleSafeValue == 1 ? 0.05f : 0.075f );
			titleSafeTall = screenTall * ( iUseTitleSafeValue == 1 ? 0.05f : 0.075f );

			// Don't title safe internal boundaries for split screen viewports
			int splitX = 0;
			int splitY = 0;
			vgui::surface()->OffsetAbsPos( splitX, splitY );

			bool bHorizontalSplit = ( alignScreenTall != screenTall );
			bool bVerticalSplit = ( alignScreenWide != screenWide );

			if ( bHorizontalSplit )
			{
				// top or bottom?
				if ( splitY != parentY )
				{
					excludeEdgeFromTitleSafe.y = 1;
				}
				else
				{
					excludeEdgeFromTitleSafe.height = 1;
				}
			}

			if ( bVerticalSplit )
			{
				// left or right
				if ( splitX != parentX )
				{
					excludeEdgeFromTitleSafe.x = 1;
				}
				else
				{
					excludeEdgeFromTitleSafe.width = 1;
				}
			}

			if ( _buildModeFlags & BUILDMODE_SAVE_XPOS_RIGHTALIGNED )
			{
				if ( !excludeEdgeFromTitleSafe.width )
				{
					x -= titleSafeWide;	// right edge
				}
			}
			else if (_buildModeFlags & BUILDMODE_SAVE_XPOS_CENTERALIGNED)
			{
			}
			else if ( !excludeEdgeFromTitleSafe.x )
			{
				x += titleSafeWide;	// left edge
			}

			if ( _buildModeFlags & BUILDMODE_SAVE_YPOS_BOTTOMALIGNED )
			{
				if ( !excludeEdgeFromTitleSafe.height )
				{
					y -= titleSafeTall;	// bottom edge
				}
			}
			else if (_buildModeFlags & BUILDMODE_SAVE_YPOS_CENTERALIGNED)
			{
			}
			else if ( !excludeEdgeFromTitleSafe.y )
			{
				y += titleSafeTall;	// top edge
			}
		}
	}
	SetNavUp( inResourceData->GetString("navUp") );
	SetNavDown( inResourceData->GetString("navDown") );
	SetNavLeft( inResourceData->GetString("navLeft") );
	SetNavRight( inResourceData->GetString("navRight") );
	SetNavToRelay( inResourceData->GetString("navToRelay") );
	SetNavActivate( inResourceData->GetString("navActivate") );
	SetNavBack( inResourceData->GetString("navBack") );

	SetPos(x, y);

	if (inResourceData->FindKey( "zpos" ))
	{
		SetZPos( inResourceData->GetInt( "zpos" ) );
	}

	if( bUsesTitleSafeArea )
	{
		if ( _buildModeFlags & BUILDMODE_SAVE_WIDE_FULL )
		{
			if ( !excludeEdgeFromTitleSafe.x )
				wide -= titleSafeWide;

			if ( !excludeEdgeFromTitleSafe.width )
				wide -= titleSafeWide;
		}

		if ( _buildModeFlags & BUILDMODE_SAVE_TALL_FULL )
		{
			if ( !excludeEdgeFromTitleSafe.y )
				tall -= titleSafeTall;

			if ( !excludeEdgeFromTitleSafe.height )
				tall -= titleSafeTall;
		}
	}

	SetSize( wide, tall );

	// NOTE: This has to happen after pos + size is set
	ApplyAutoResizeSettings( inResourceData );

	// only get colors if we're ignoring the scheme
	if (inResourceData->GetInt("IgnoreScheme", 0))
	{
		PerformApplySchemeSettings();
	}

	// state
	int state = inResourceData->GetInt("visible", 1);
	if (state == 0)
	{
		SetVisible(false);
	}
	else if (state == 1)
	{
		SetVisible(true);
	}

	SetEnabled( inResourceData->GetInt("enabled", true) );

	bool bMouseEnabled = inResourceData->GetInt( "mouseinputenabled", true );
	if ( !bMouseEnabled )
	{
		SetMouseInputEnabled( false );
	}

	// tab order
	SetTabPosition(inResourceData->GetInt("tabPosition", 0));

	const char *tooltip = inResourceData->GetString("tooltiptext", NULL);
	if (tooltip && *tooltip)
	{
		GetTooltip()->SetText(tooltip);
	}

	// paint background?
	int nPaintBackground = inResourceData->GetInt("paintbackground", -1);
	if (nPaintBackground >= 0)
	{
		SetPaintBackgroundEnabled( nPaintBackground != 0 );
	}

	// paint border?
	int nPaintBorder = inResourceData->GetInt("paintborder", -1);
	if (nPaintBorder >= 0)
	{
		SetPaintBorderEnabled( nPaintBorder != 0 );
	}

	// border?
	const char *pBorder = inResourceData->GetString( "border", "" );
	if ( *pBorder )
	{
		IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
		SetBorder( pScheme->GetBorder( pBorder ) );
	}

	// check to see if we have a new name assigned
	const char *newName = inResourceData->GetString("fieldName", NULL);
	if ( newName )
	{
		// Only slam the name if the new one differs...
		SetName(newName);
	}

	tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s: Action signal", __FUNCTION__, GetName() );
	// Automatically add an action signal target if one is specified.  This allows for
	// nested child buttons to add their distant parents as action signal targets.
	int nActionSignalLevel = inResourceData->GetInt( "actionsignallevel", -1 );
	if ( nActionSignalLevel != -1 )
	{
		Panel *pActionSignalTarget = this;
		while( nActionSignalLevel-- )
		{
			pActionSignalTarget = pActionSignalTarget->GetParent();
		}
		AddActionSignalTarget( pActionSignalTarget );
	}

	// check to see if we need to render to the frame buffer even if 
	// stereo mode is trying to render all of the ui to a render target
	m_bForceStereoRenderToFrameBuffer = inResourceData->GetBool( "ForceStereoRenderToFrameBuffer", false );
 
	//=============================================================================
	// HPE_BEGIN:
	// [pfreese] Support for reading rounded corner flags
	//=============================================================================
	int roundedCorners = inResourceData->GetInt( "RoundedCorners", -1 );
	if ( roundedCorners >= 0 )
	{
		m_roundedCorners = roundedCorners;
	}
	//=============================================================================
	// HPE_END
	//=============================================================================

	tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s: Pin Sibling", __FUNCTION__, GetName() );
	const char *pszSiblingName = inResourceData->GetString("pin_to_sibling", NULL);
	PinCorner_e pinOurCornerToSibling = GetPinCornerFromString( inResourceData->GetString( "pin_corner_to_sibling", NULL ) );
	PinCorner_e pinSiblingCorner = GetPinCornerFromString( inResourceData->GetString( "pin_to_sibling_corner", NULL ) );
	PinToSibling( pszSiblingName, pinOurCornerToSibling, pinSiblingCorner );


	tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s: Color overrides", __FUNCTION__, GetName() );
	// Allow overriding of colors. Used mostly by HUD elements, where scheme color usage is often undesired.
	IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
	for ( int i = 0; i < m_OverridableColorEntries.Count(); i++ )
	{
		// Need to ensure the key exists, so we don't overwrite existing colors when it's not set.
		if ( inResourceData->FindKey( m_OverridableColorEntries[i].m_pszScriptName, false ) )
		{
			// Get the color as a string - test whether it is an actual color or a reference to a scheme color
			const char *pColorStr = inResourceData->GetString( m_OverridableColorEntries[i].m_pszScriptName );
			Color &clrDest = m_OverridableColorEntries[i].m_colFromScript;
			if ( pColorStr[0] == '.' || isdigit( pColorStr[0] ) )
			{
				float r = 0.0f, g = 0.0f, b = 0.0f, a = 0.0f;
				sscanf( pColorStr, "%f %f %f %f", &r, &g, &b, &a );
				clrDest[0] = (unsigned char)r;
				clrDest[1] = (unsigned char)g;
				clrDest[2] = (unsigned char)b;
				clrDest[3] = (unsigned char)a;
			}
			else
			{
				// First character wasn't a digit or a decimal - do a scheme color lookup
				clrDest = pScheme->GetColor( pColorStr, Color( 255, 255, 255, 255 ) );
			}

			(*m_OverridableColorEntries[i].m_pColor) = m_OverridableColorEntries[i].m_colFromScript;
			m_OverridableColorEntries[i].m_bOverridden = true;
		}
	}

	tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s: Keyboard enabled", __FUNCTION__, GetName() );
	const char *pKeyboardInputEnabled = inResourceData->GetString( "keyboardinputenabled", NULL );
	if ( pKeyboardInputEnabled && pKeyboardInputEnabled[0] )
	{
		SetKeyBoardInputEnabled( atoi( pKeyboardInputEnabled ) );
	}

	OnChildSettingsApplied( inResourceData, this );
}

//-----------------------------------------------------------------------------
// Purpose: Saves out a resource description of this panel
//-----------------------------------------------------------------------------
void Panel::GetSettings( KeyValues *outResourceData )
{
	// control class name (so it can be recreated later if needed)
	outResourceData->SetString( "ControlName", GetClassName() );

	// name
	outResourceData->SetString( "fieldName", _panelName );

	// positioning
	int screenWide, screenTall;
	surface()->GetScreenSize(screenWide, screenTall);
	int x, y;
	GetPos( x, y );
	if ( IsProportional() )
	{
		x = scheme()->GetProportionalNormalizedValueEx( GetScheme(), x );
		y = scheme()->GetProportionalNormalizedValueEx( GetScheme(), y );
	}
	// correct for alignment
	if (_buildModeFlags & BUILDMODE_SAVE_XPOS_RIGHTALIGNED)
	{
		x = screenWide - x;
		char xstr[32];
		Q_snprintf(xstr, sizeof( xstr ), "r%d", x);
		outResourceData->SetString( "xpos", xstr );
	}
	else if (_buildModeFlags & BUILDMODE_SAVE_XPOS_CENTERALIGNED)
	{
		x = (screenWide / 2) + x;
		char xstr[32];
		Q_snprintf(xstr, sizeof( xstr ), "c%d", x);
		outResourceData->SetString( "xpos", xstr );
	}
	else
	{
		outResourceData->SetInt( "xpos", x );
	}
	if (_buildModeFlags & BUILDMODE_SAVE_YPOS_BOTTOMALIGNED)
	{
		y = screenTall - y;
		char ystr[32];
		Q_snprintf(ystr, sizeof( ystr ), "r%d", y);
		outResourceData->SetString( "ypos", ystr );
	}
	else if (_buildModeFlags & BUILDMODE_SAVE_YPOS_CENTERALIGNED)
	{
		y = (screenTall / 2) + y;
		char ystr[32];
		Q_snprintf(ystr, sizeof( ystr ), "c%d", y);
		outResourceData->SetString( "ypos", ystr );
	}
	else
	{
		outResourceData->SetInt( "ypos", y );
	}
	if (m_pTooltips)
	{
		if (strlen(m_pTooltips->GetText()) > 0)
		{
			outResourceData->SetString("tooltiptext", m_pTooltips->GetText());
		}
	}
	int wide, tall;
	GetSize( wide, tall );
	if ( IsProportional() )
	{
		wide = scheme()->GetProportionalNormalizedValueEx( GetScheme(), wide );
		tall = scheme()->GetProportionalNormalizedValueEx( GetScheme(), tall );
	}

	int z = ipanel()->GetZPos(GetVPanel());
	if (z)
	{
		outResourceData->SetInt("zpos", z);
	}

	// Correct for alignment
	if (_buildModeFlags & BUILDMODE_SAVE_WIDE_FULL )
	{
		wide = screenWide - wide;
		char wstr[32];
		Q_snprintf(wstr, sizeof( wstr ), "f%d", wide);
		outResourceData->SetString( "wide", wstr );
	}
	else
	{
		outResourceData->SetInt( "wide", wide );
	}
	outResourceData->SetInt( "tall", tall );

	outResourceData->SetInt("AutoResize", GetAutoResize());
	outResourceData->SetInt("PinCorner", GetPinCorner());

	//=============================================================================
	// HPE_BEGIN:
	// [pfreese] Support for writing out rounded corner flags
	//=============================================================================
	outResourceData->SetInt("RoundedCorners", m_roundedCorners);
	//=============================================================================
	// HPE_END
	//=============================================================================

	outResourceData->SetString( "pin_to_sibling", _pinToSibling );
	outResourceData->SetInt("pin_corner_to_sibling", _pinCornerToSibling );
	outResourceData->SetInt("pin_to_sibling_corner", _pinToSiblingCorner );


	// state
	outResourceData->SetInt( "visible", IsVisible() );
	outResourceData->SetInt( "enabled", IsEnabled() );

	outResourceData->SetInt( "tabPosition", GetTabPosition() );

	for ( int i = 0; i < m_OverridableColorEntries.Count(); i++ )
	{
		if ( m_OverridableColorEntries[i].m_bOverridden )
		{
			outResourceData->SetColor( m_OverridableColorEntries[i].m_pszScriptName, m_OverridableColorEntries[i].m_colFromScript );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: After applying settings, apply overridable colors.
//			Done post apply settings, so that baseclass settings don't stomp
//			the script specified override colors.
//-----------------------------------------------------------------------------
void Panel::ApplyOverridableColors( void )
{
	for ( int i = 0; i < m_OverridableColorEntries.Count(); i++ )
	{
		if ( m_OverridableColorEntries[i].m_bOverridden )
		{
			(*m_OverridableColorEntries[i].m_pColor) = m_OverridableColorEntries[i].m_colFromScript;
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::SetOverridableColor( Color *pColor, const Color &newColor )
{
	for ( int i = 0; i < m_OverridableColorEntries.Count(); i++ )
	{
		if ( m_OverridableColorEntries[i].m_bOverridden )
		{
			if ( m_OverridableColorEntries[i].m_pColor == pColor )
				return;
		}
	}

	// Didn't find it, or it's not been overridden.
	*pColor = newColor;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
Color Panel::GetSchemeColor(const char *keyName, IScheme *pScheme)
{
	return pScheme->GetColor(keyName, Color(255, 255, 255, 255));
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
Color Panel::GetSchemeColor(const char *keyName, Color defaultColor, IScheme *pScheme)
{
	return pScheme->GetColor(keyName, defaultColor);
}

//-----------------------------------------------------------------------------
// Purpose: Returns a string description of the panel fields for use in the UI
//-----------------------------------------------------------------------------
const char *Panel::GetDescription( void )
{
	static const char *panelDescription = "string fieldName, int xpos, int ypos, int wide, int tall, bool visible, bool enabled, int tabPosition, corner pinCorner, autoresize autoResize, string tooltiptext";
	return panelDescription;
}

//-----------------------------------------------------------------------------
// Purpose: user configuration settings
//			this is used for any control details the user wants saved between sessions
//			eg. dialog positions, last directory opened, list column width
//-----------------------------------------------------------------------------
void Panel::ApplyUserConfigSettings(KeyValues *userConfig)
{
}

//-----------------------------------------------------------------------------
// Purpose: returns user config settings for this control
//-----------------------------------------------------------------------------
void Panel::GetUserConfigSettings(KeyValues *userConfig)
{
}

//-----------------------------------------------------------------------------
// Purpose: optimization, return true if this control has any user config settings
//-----------------------------------------------------------------------------
bool Panel::HasUserConfigSettings()
{
	return false;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::InternalInvalidateLayout()
{
	InvalidateLayout(false, false);
}

//-----------------------------------------------------------------------------
// Purpose: called whenever the panel moves
//-----------------------------------------------------------------------------
void Panel::OnMove()
{
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::InternalMove()
{
	OnMove();
	for(int i=0;i<GetChildCount();i++)
	{
		// recursively apply to all children
		GetChild(i)->OnMove();
	}
}

//-----------------------------------------------------------------------------
// Purpose: empty function
//-----------------------------------------------------------------------------
void Panel::OnTick()
{
}

//-----------------------------------------------------------------------------
// Purpose: versioning
//-----------------------------------------------------------------------------
void *Panel::QueryInterface(EInterfaceID id)
{
	if (id == ICLIENTPANEL_STANDARD_INTERFACE)
	{
		return this;
	}

	return NULL;
}


//-----------------------------------------------------------------------------
// Purpose: Map all the base messages to functions
//			ordering from most -> least used improves speed
//-----------------------------------------------------------------------------
MessageMapItem_t Panel::m_MessageMap[] =
{
	MAP_MESSAGE_INT( Panel, "RequestFocus", RequestFocus, "direction" )
};

// IMPLEMENT_PANELMAP( Panel, NULL )
PanelMap_t Panel::m_PanelMap = { Panel::m_MessageMap, ARRAYSIZE(Panel::m_MessageMap), "Panel", NULL };
PanelMap_t *Panel::GetPanelMap( void ) { return &m_PanelMap; }

//-----------------------------------------------------------------------------
// Purpose: !! Soon to replace existing prepare panel map
//-----------------------------------------------------------------------------
void PreparePanelMessageMap(PanelMessageMap *panelMap)
{
	// iterate through the class hierarchy message maps
	while ( panelMap != NULL && !panelMap->processed )
	{
		// hash message map strings into symbols
		for (int i = 0; i < panelMap->entries.Count(); i++)
		{
			MessageMapItem_t *item = &panelMap->entries[i];

			if (item->name)
			{
				item->nameSymbol = KeyValuesSystem()->GetSymbolForString(item->name);
			}
			else
			{
				item->nameSymbol = INVALID_KEY_SYMBOL;
			}
			if (item->firstParamName)
			{
				item->firstParamSymbol = KeyValuesSystem()->GetSymbolForString(item->firstParamName);
			}
			else
			{
				item->firstParamSymbol = INVALID_KEY_SYMBOL;
			}
			if (item->secondParamName)
			{
				item->secondParamSymbol = KeyValuesSystem()->GetSymbolForString(item->secondParamName);
			}
			else
			{
				item->secondParamSymbol = INVALID_KEY_SYMBOL;
			}
		}
		
		panelMap->processed = true;
		panelMap = panelMap->baseMap;
	}
}



//-----------------------------------------------------------------------------
// Purpose: Handles a message
//			Dispatches the message to a set of message maps
//-----------------------------------------------------------------------------
void Panel::OnMessage(const KeyValues *params, VPANEL ifromPanel)
{
	PanelMessageMap *panelMap = GetMessageMap();
	bool bFound = false;
	int iMessageName = params->GetNameSymbol();

	if ( !panelMap->processed )
	{
		PreparePanelMessageMap( panelMap );
	}

	// iterate through the class hierarchy message maps
	for ( ; panelMap != NULL && !bFound; panelMap = panelMap->baseMap )
	{
#if defined( _DEBUG )
//		char const *className = panelMap->pfnClassName();
//		NOTE_UNUSED( className );
#endif

		// iterate all the entries in the panel map
		for ( int i = 0; i < panelMap->entries.Count(); i++ )
		{
			MessageMapItem_t *pMap = &panelMap->entries[i];

			if (iMessageName == pMap->nameSymbol)
			{
				bFound = true;

				switch (pMap->numParams)
				{
				case 0:
				{
					(this->*(pMap->func))();
					break;
				}
		
				case 1:
				{
					KeyValues *param1 = params->FindKey(pMap->firstParamSymbol);
					if (!param1)
					{
						param1 = const_cast<KeyValues *>(params);
					}

					switch ( pMap->firstParamType )
					{
						case DATATYPE_INT:
							typedef void (Panel::*MessageFunc_Int_t)(int);
							(this->*((MessageFunc_Int_t)pMap->func))( param1->GetInt() );
							break;

						case DATATYPE_UINT64:
							typedef void (Panel::*MessageFunc_Uin64_t)(uint64);
							(this->*((MessageFunc_Uin64_t)pMap->func))( param1->GetUint64() );
							break;

						case DATATYPE_PTR:
							typedef void (Panel::*MessageFunc_Ptr_t)( void * );
							(this->*((MessageFunc_Ptr_t)pMap->func))( param1->GetPtr() );
							break;

						case DATATYPE_HANDLE:
							{
								typedef void (Panel::*MessageFunc_VPANEL_t)( VPANEL );
								VPANEL vpanel = ivgui()->HandleToPanel( param1->GetInt() );
								(this->*((MessageFunc_VPANEL_t)pMap->func))( vpanel );
							}
							break;

						case DATATYPE_FLOAT:
							typedef void (Panel::*MessageFunc_Float_t)( float );
							(this->*((MessageFunc_Float_t)pMap->func))( param1->GetFloat() );
							break;

						case DATATYPE_CONSTCHARPTR:
							typedef void (Panel::*MessageFunc_CharPtr_t)( const char * );
							(this->*((MessageFunc_CharPtr_t)pMap->func))( param1->GetString() );
							break;

						case DATATYPE_CONSTWCHARPTR:
							typedef void (Panel::*MessageFunc_WCharPtr_t)( const wchar_t * );
							(this->*((MessageFunc_WCharPtr_t)pMap->func))( param1->GetWString() );
							break;

						case DATATYPE_KEYVALUES:
							typedef void (Panel::*MessageFunc_KeyValues_t)(KeyValues *);
							if ( pMap->firstParamName )
							{
								(this->*((MessageFunc_KeyValues_t)pMap->func))( (KeyValues *)param1->GetPtr() );
							}
							else
							{
								// no param set, so pass in the whole thing
								(this->*((MessageFunc_KeyValues_t)pMap->func))( const_cast<KeyValues *>(params) );
							}
							break;

						default:
							Assert(!("No handler for vgui message function"));
							break;
					}
					break;
				}

				case 2:
				{
					KeyValues *param1 = params->FindKey(pMap->firstParamSymbol);
					if (!param1)
					{
						param1 = const_cast<KeyValues *>(params);
					}
					KeyValues *param2 = params->FindKey(pMap->secondParamSymbol);
					if (!param2)
					{
						param2 = const_cast<KeyValues *>(params);
					}

					if ( (DATATYPE_INT == pMap->firstParamType) && (DATATYPE_INT == pMap->secondParamType) )
					{
						typedef void (Panel::*MessageFunc_IntInt_t)(int, int);
						(this->*((MessageFunc_IntInt_t)pMap->func))( param1->GetInt(), param2->GetInt() );
					}
					else if ( (DATATYPE_PTR == pMap->firstParamType) && (DATATYPE_INT == pMap->secondParamType) )
					{
						typedef void (Panel::*MessageFunc_PtrInt_t)(void *, int);
						(this->*((MessageFunc_PtrInt_t)pMap->func))( param1->GetPtr(), param2->GetInt() );
					}
					else if ( (DATATYPE_CONSTCHARPTR == pMap->firstParamType) && (DATATYPE_INT == pMap->secondParamType) )
					{
						typedef void (Panel::*MessageFunc_ConstCharPtrInt_t)(const char *, int);
						(this->*((MessageFunc_ConstCharPtrInt_t)pMap->func))( param1->GetString(), param2->GetInt() );
					}
					else if ( (DATATYPE_CONSTCHARPTR == pMap->firstParamType) && (DATATYPE_CONSTCHARPTR == pMap->secondParamType) )
					{
						typedef void (Panel::*MessageFunc_ConstCharPtrConstCharPtr_t)(const char *, const char *);
						(this->*((MessageFunc_ConstCharPtrConstCharPtr_t)pMap->func))( param1->GetString(), param2->GetString() );
					}
					else if ( (DATATYPE_INT == pMap->firstParamType) && (DATATYPE_CONSTCHARPTR == pMap->secondParamType) )
					{
						typedef void (Panel::*MessageFunc_IntConstCharPtr_t)(int, const char *);
						(this->*((MessageFunc_IntConstCharPtr_t)pMap->func))( param1->GetInt(), param2->GetString() );
					}
					else if ( (DATATYPE_PTR == pMap->firstParamType) && (DATATYPE_CONSTCHARPTR == pMap->secondParamType) )
					{
						typedef void (Panel::*MessageFunc_PtrConstCharPtr_t)(void *, const char *);
						(this->*((MessageFunc_PtrConstCharPtr_t)pMap->func))( param1->GetPtr(), param2->GetString() );
					}
					else if ( (DATATYPE_PTR == pMap->firstParamType) && (DATATYPE_CONSTWCHARPTR == pMap->secondParamType) )
					{
						typedef void (Panel::*MessageFunc_PtrConstCharPtr_t)(void *, const wchar_t *);
						(this->*((MessageFunc_PtrConstCharPtr_t)pMap->func))( param1->GetPtr(), param2->GetWString() );
					}
					else if ( (DATATYPE_HANDLE == pMap->firstParamType) && (DATATYPE_CONSTCHARPTR == pMap->secondParamType) )
					{
						typedef void (Panel::*MessageFunc_HandleConstCharPtr_t)(VPANEL, const char *);
						VPANEL vp = ivgui()->HandleToPanel( param1->GetInt() );
						(this->*((MessageFunc_HandleConstCharPtr_t)pMap->func))( vp, param2->GetString() );
					}
					else if ( (DATATYPE_HANDLE == pMap->firstParamType) && (DATATYPE_CONSTWCHARPTR == pMap->secondParamType) )
					{
						typedef void (Panel::*MessageFunc_HandleConstCharPtr_t)(VPANEL, const wchar_t *);
						VPANEL vp = ivgui()->HandleToPanel( param1->GetInt() );
						(this->*((MessageFunc_HandleConstCharPtr_t)pMap->func))( vp, param2->GetWString() );
					}
					else if ( (DATATYPE_HANDLE == pMap->firstParamType) && (DATATYPE_HANDLE == pMap->secondParamType) )
					{
						typedef void (Panel::*MessageFunc_HandleConstCharPtr_t)(VPANEL, VPANEL);
						VPANEL vp1 = ivgui()->HandleToPanel( param1->GetInt() );
						VPANEL vp2 = ivgui()->HandleToPanel( param2->GetInt() );
						(this->*((MessageFunc_HandleConstCharPtr_t)pMap->func))( vp1, vp2 );
					}
					else
					{
						// the message isn't handled
						ivgui()->DPrintf( "Message '%s', sent to '%s', has invalid parameter types\n", params->GetName(), GetName() );
					}
					break;
				}

				default:
					Assert(!("Invalid number of parameters"));
					break;
				}

				// break the loop
				bFound = true;
				break;
			}
		}
	}

	if (!bFound)
	{
		OnOldMessage(const_cast<KeyValues *>(params), ifromPanel);
	}
}

void Panel::OnOldMessage(KeyValues *params, VPANEL ifromPanel)
{
	bool bFound = false;
	// message map dispatch
	int iMessageName = params->GetNameSymbol();

	PanelMap_t *panelMap = GetPanelMap();
	if ( !panelMap->processed )
	{
		PreparePanelMap( panelMap );
	}

	// iterate through the class hierarchy message maps
	for ( ; panelMap != NULL && !bFound; panelMap = panelMap->baseMap )
	{
		MessageMapItem_t *pMessageMap = panelMap->dataDesc;

		for ( int i = 0; i < panelMap->dataNumFields; i++ )
		{
			if (iMessageName == pMessageMap[i].nameSymbol)
			{
				// call the mapped function
				switch ( pMessageMap[i].numParams )
				{
				case 2:
					if ( (DATATYPE_INT == pMessageMap[i].firstParamType) && (DATATYPE_INT == pMessageMap[i].secondParamType) )
					{
						typedef void (Panel::*MessageFunc_IntInt_t)(int, int);
						(this->*((MessageFunc_IntInt_t)pMessageMap[i].func))( params->GetInt(pMessageMap[i].firstParamName), params->GetInt(pMessageMap[i].secondParamName) );
					}
					else if ( (DATATYPE_PTR == pMessageMap[i].firstParamType) && (DATATYPE_INT == pMessageMap[i].secondParamType) )
					{
						typedef void (Panel::*MessageFunc_PtrInt_t)(void *, int);
						(this->*((MessageFunc_PtrInt_t)pMessageMap[i].func))( params->GetPtr(pMessageMap[i].firstParamName), params->GetInt(pMessageMap[i].secondParamName) );
					}
					else if ( (DATATYPE_CONSTCHARPTR == pMessageMap[i].firstParamType) && (DATATYPE_INT == pMessageMap[i].secondParamType) )
					{
						typedef void (Panel::*MessageFunc_ConstCharPtrInt_t)(const char *, int);
						(this->*((MessageFunc_ConstCharPtrInt_t)pMessageMap[i].func))( params->GetString(pMessageMap[i].firstParamName), params->GetInt(pMessageMap[i].secondParamName) );
					}
					else if ( (DATATYPE_CONSTCHARPTR == pMessageMap[i].firstParamType) && (DATATYPE_CONSTCHARPTR == pMessageMap[i].secondParamType) )
					{
						typedef void (Panel::*MessageFunc_ConstCharPtrConstCharPtr_t)(const char *, const char *);
						(this->*((MessageFunc_ConstCharPtrConstCharPtr_t)pMessageMap[i].func))( params->GetString(pMessageMap[i].firstParamName), params->GetString(pMessageMap[i].secondParamName) );
					}
					else if ( (DATATYPE_INT == pMessageMap[i].firstParamType) && (DATATYPE_CONSTCHARPTR == pMessageMap[i].secondParamType) )
					{
						typedef void (Panel::*MessageFunc_IntConstCharPtr_t)(int, const char *);
						(this->*((MessageFunc_IntConstCharPtr_t)pMessageMap[i].func))( params->GetInt(pMessageMap[i].firstParamName), params->GetString(pMessageMap[i].secondParamName) );
					}
					else if ( (DATATYPE_PTR == pMessageMap[i].firstParamType) && (DATATYPE_CONSTCHARPTR == pMessageMap[i].secondParamType) )
					{
						typedef void (Panel::*MessageFunc_PtrConstCharPtr_t)(void *, const char *);
						(this->*((MessageFunc_PtrConstCharPtr_t)pMessageMap[i].func))( params->GetPtr(pMessageMap[i].firstParamName), params->GetString(pMessageMap[i].secondParamName) );
					}
					else if ( (DATATYPE_PTR == pMessageMap[i].firstParamType) && (DATATYPE_CONSTWCHARPTR == pMessageMap[i].secondParamType) )
					{
						typedef void (Panel::*MessageFunc_PtrConstCharPtr_t)(void *, const wchar_t *);
						(this->*((MessageFunc_PtrConstCharPtr_t)pMessageMap[i].func))( params->GetPtr(pMessageMap[i].firstParamName), params->GetWString(pMessageMap[i].secondParamName) );
					}
					else if ( (DATATYPE_HANDLE == pMessageMap[i].firstParamType) && (DATATYPE_CONSTCHARPTR ==pMessageMap[i].secondParamType) )
					{
						typedef void (Panel::*MessageFunc_HandleConstCharPtr_t)(VPANEL, const char *);
						VPANEL vp = ivgui()->HandleToPanel( params->GetInt( pMessageMap[i].firstParamName ) );
						(this->*((MessageFunc_HandleConstCharPtr_t)pMessageMap[i].func))( vp, params->GetString(pMessageMap[i].secondParamName) );
					}
					else if ( (DATATYPE_HANDLE == pMessageMap[i].firstParamType) && (DATATYPE_CONSTWCHARPTR == pMessageMap[i].secondParamType) )
					{
						typedef void (Panel::*MessageFunc_HandleConstCharPtr_t)(VPANEL, const wchar_t *);
						VPANEL vp = ivgui()->HandleToPanel( params->GetInt( pMessageMap[i].firstParamName ) );
						(this->*((MessageFunc_HandleConstCharPtr_t)pMessageMap[i].func))( vp, params->GetWString(pMessageMap[i].secondParamName) );
					}
					else
					{
						// the message isn't handled
						ivgui()->DPrintf( "Message '%s', sent to '%s', has invalid parameter types\n", params->GetName(), GetName() );
					}
					break;

				case 1:
					switch ( pMessageMap[i].firstParamType )
					{
					case DATATYPE_BOOL:
						typedef void (Panel::*MessageFunc_Bool_t)(bool);
						(this->*((MessageFunc_Bool_t)pMessageMap[i].func))( (bool)params->GetInt(pMessageMap[i].firstParamName) );
						break;

					case DATATYPE_CONSTCHARPTR:
						typedef void (Panel::*MessageFunc_ConstCharPtr_t)(const char *);
						(this->*((MessageFunc_ConstCharPtr_t)pMessageMap[i].func))( (const char *)params->GetString(pMessageMap[i].firstParamName) );
						break;

					case DATATYPE_CONSTWCHARPTR:
						typedef void (Panel::*MessageFunc_ConstCharPtr_t)(const char *);
						(this->*((MessageFunc_ConstCharPtr_t)pMessageMap[i].func))( (const char *)params->GetWString(pMessageMap[i].firstParamName) );
						break;

					case DATATYPE_INT:
						typedef void (Panel::*MessageFunc_Int_t)(int);
						(this->*((MessageFunc_Int_t)pMessageMap[i].func))( params->GetInt(pMessageMap[i].firstParamName) );
						break;

					case DATATYPE_FLOAT:
						typedef void (Panel::*MessageFunc_Float_t)(float);
						(this->*((MessageFunc_Float_t)pMessageMap[i].func))( params->GetFloat(pMessageMap[i].firstParamName) );
						break;

					case DATATYPE_PTR:
						typedef void (Panel::*MessageFunc_Ptr_t)(void *);
						(this->*((MessageFunc_Ptr_t)pMessageMap[i].func))( (void *)params->GetPtr(pMessageMap[i].firstParamName) );
						break;
					
					case DATATYPE_HANDLE:
						{
							typedef void (Panel::*MessageFunc_Ptr_t)(void *);
							VPANEL vp = ivgui()->HandleToPanel( params->GetInt( pMessageMap[i].firstParamName ) );
							Panel *panel = ipanel()->GetPanel( vp, GetModuleName() );
							(this->*((MessageFunc_Ptr_t)pMessageMap[i].func))( (void *)panel );
						}
						break;

					case DATATYPE_KEYVALUES:
						typedef void (Panel::*MessageFunc_KeyValues_t)(KeyValues *);
						if ( pMessageMap[i].firstParamName )
						{
							(this->*((MessageFunc_KeyValues_t)pMessageMap[i].func))( (KeyValues *)params->GetPtr(pMessageMap[i].firstParamName) );
						}
						else
						{
							(this->*((MessageFunc_KeyValues_t)pMessageMap[i].func))( params );
						}
						break;

					default:
						// the message isn't handled
						ivgui()->DPrintf( "Message '%s', sent to '%s', has an invalid parameter type\n", params->GetName(), GetName() );
						break;
					}

					break;

				default:
					(this->*(pMessageMap[i].func))();
					break;
				};

				// break the loop
				bFound = true;
				break;
			}
		}
	}

	// message not handled
	// debug code
	if ( !bFound )
	{
		static int s_bDebugMessages = -1;
		if ( s_bDebugMessages == -1 )
		{
			s_bDebugMessages = CommandLine()->FindParm( "-vguimessages" ) ? 1 : 0;
		}
		if ( s_bDebugMessages == 1 )
		{
			ivgui()->DPrintf( "Message '%s' not handled by panel '%s'\n", params->GetName(), GetName() );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Safe call to get info from child panel by name
//-----------------------------------------------------------------------------
bool Panel::RequestInfoFromChild(const char *childName, KeyValues *outputData)
{
	Panel *panel = FindChildByName(childName);
	if (panel)
	{
		return panel->RequestInfo(outputData);
	}
	return false;
}

//-----------------------------------------------------------------------------
// Purpose: Posts a message
//-----------------------------------------------------------------------------
void Panel::PostMessage(Panel *target, KeyValues *message, float delay)
{
	ivgui()->PostMessage(target->GetVPanel(), message, GetVPanel(), delay);
}

void Panel::PostMessage(VPANEL target, KeyValues *message, float delaySeconds)
{
	ivgui()->PostMessage(target, message, GetVPanel(), delaySeconds);
}

void Panel::PostMessageToAllSiblings( KeyValues *msg, float delaySeconds /*= 0.0f*/ )
{
	VPANEL parent = GetVParent();
	if ( parent )
	{
		VPANEL vpanel = GetVPanel();

		CUtlVector< VPANEL > &children = ipanel()->GetChildren( parent );
		int nChildCount = children.Count();
		for ( int i = 0; i < nChildCount; ++i )
		{
			VPANEL sibling = children[ i ];
			if ( sibling == vpanel )
				continue;

			if ( sibling )
			{
				PostMessage( sibling, msg->MakeCopy(), delaySeconds );
			}
		}
	}

	msg->deleteThis();
}

//-----------------------------------------------------------------------------
// Purpose: Safe call to post a message to a child by name
//-----------------------------------------------------------------------------
void Panel::PostMessageToChild(const char *childName, KeyValues *message)
{
	Panel *panel = FindChildByName(childName);
	if (panel)
	{
		ivgui()->PostMessage(panel->GetVPanel(), message, GetVPanel());
	}
	else
	{
		message->deleteThis();
	}
}

//-----------------------------------------------------------------------------
// Purpose: Requests some information from the panel
//			Look through the message map for the handler
//-----------------------------------------------------------------------------
bool Panel::RequestInfo( KeyValues *outputData )
{
	if ( InternalRequestInfo( GetAnimMap(), outputData ) )
	{
		return true;
	}

	if (GetVParent())
	{
		return ipanel()->RequestInfo(GetVParent(), outputData);
	}

	return false;
}

//-----------------------------------------------------------------------------
// Purpose: sets a specified value in the control - inverse of RequestInfo
//-----------------------------------------------------------------------------
bool Panel::SetInfo(KeyValues *inputData)
{
	if ( InternalSetInfo( GetAnimMap(), inputData ) )
	{
		return true;
	}

	// doesn't chain to parent
	return false;
}

//-----------------------------------------------------------------------------
// Purpose: change the panel's silent mode; if silent, the panel will not post
//			any action signals
//-----------------------------------------------------------------------------

void Panel::SetSilentMode( bool bSilent )
{
	m_bIsSilent = bSilent;
}

//-----------------------------------------------------------------------------
// Purpose: mouse events will be send to handler panel instead of this panel
//-----------------------------------------------------------------------------
void Panel::InstallMouseHandler( Panel *pHandler )
{
	m_hMouseEventHandler = pHandler;
}

//-----------------------------------------------------------------------------
// Purpose: Prepares the hierarchy panel maps for use (with message maps etc)
//-----------------------------------------------------------------------------
void Panel::PreparePanelMap( PanelMap_t *panelMap )
{
	// iterate through the class hierarchy message maps
	while ( panelMap != NULL && !panelMap->processed )
	{
		// fixup cross-dll boundary panel maps
		if ( panelMap->baseMap == (PanelMap_t*)0x00000001 )
		{
			panelMap->baseMap = &Panel::m_PanelMap;
		}

		// hash message map strings into symbols
		for (int i = 0; i < panelMap->dataNumFields; i++)
		{
			MessageMapItem_t *item = &panelMap->dataDesc[i];

			if (item->name)
			{
				item->nameSymbol = KeyValuesSystem()->GetSymbolForString(item->name);
			}
			else
			{
				item->nameSymbol = INVALID_KEY_SYMBOL;
			}
			if (item->firstParamName)
			{
				item->firstParamSymbol = KeyValuesSystem()->GetSymbolForString(item->firstParamName);
			}
			else
			{
				item->firstParamSymbol = INVALID_KEY_SYMBOL;
			}
			if (item->secondParamName)
			{
				item->secondParamSymbol = KeyValuesSystem()->GetSymbolForString(item->secondParamName);
			}
			else
			{
				item->secondParamSymbol = INVALID_KEY_SYMBOL;
			}
		}
		
		panelMap->processed = true;
		panelMap = panelMap->baseMap;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Called to delete the panel
//-----------------------------------------------------------------------------
void Panel::OnDelete()
{
#ifdef WIN32
	Assert( IsX360() || ( IsPC() && _heapchk() == _HEAPOK ) );
#endif
	delete this;
#ifdef WIN32
	Assert( IsX360() || ( IsPC() && _heapchk() == _HEAPOK ) );
#endif
}

//-----------------------------------------------------------------------------
// Purpose: Panel handle implementation
//			Returns a pointer to a valid panel, NULL if the panel has been deleted
//-----------------------------------------------------------------------------
Panel *PHandle::Get() const
{
	if (m_iPanelID != INVALID_PANEL)
	{
		VPANEL panel = ivgui()->HandleToPanel(m_iPanelID);
		if (panel)
		{
			Panel *vguiPanel = ipanel()->GetPanel(panel, GetControlsModuleName());
			return vguiPanel;
		}
	}
	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose: sets the smart pointer
//-----------------------------------------------------------------------------
Panel *PHandle::Set(Panel *pent)
{
	if (pent)
	{
		m_iPanelID = ivgui()->PanelToHandle(pent->GetVPanel());
	}
	else
	{
		m_iPanelID = INVALID_PANEL;
	}
	return pent; 
}

Panel *PHandle::Set( HPanel hPanel )
{
	m_iPanelID = hPanel;
	return Get();
}


//-----------------------------------------------------------------------------
// Purpose: Returns a handle to a valid panel, NULL if the panel has been deleted
//-----------------------------------------------------------------------------
VPANEL VPanelHandle::Get()
{
	if (m_iPanelID != INVALID_PANEL)
	{
        if (ivgui())
        {
		    return ivgui()->HandleToPanel(m_iPanelID);
        }
	}
	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose: sets the smart pointer
//-----------------------------------------------------------------------------
VPANEL VPanelHandle::Set(VPANEL pent)
{
	if (pent)
	{
		m_iPanelID = ivgui()->PanelToHandle(pent);
	}
	else
	{
		m_iPanelID = INVALID_PANEL;
	}
	return pent; 
}

//-----------------------------------------------------------------------------
// Purpose: returns a pointer to the tooltip object associated with the panel
//-----------------------------------------------------------------------------
BaseTooltip *Panel::GetTooltip()
{
	if (!m_pTooltips)
	{
		m_pTooltips = new TextTooltip(this, NULL);
		m_bToolTipOverridden = false;
		
		if ( IsConsoleStylePanel() )
		{
			m_pTooltips->SetEnabled( false );
		}
	}

	return m_pTooltips;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::SetTooltip( BaseTooltip *pToolTip, const char *pszText )
{
	if ( !m_bToolTipOverridden )
	{
		// Remove the one we made, we're being overridden.
		delete m_pTooltips;
	}

	m_pTooltips = pToolTip;
	m_bToolTipOverridden = true;

	if ( _tooltipText )
	{
		delete [] _tooltipText;
		_tooltipText = NULL;
	}

	if ( pszText )
	{
		int len = Q_strlen(pszText) + 1;
		_tooltipText = new char[ len ];
		Q_strncpy( _tooltipText, pszText, len );
	}
}

//-----------------------------------------------------------------------------
const char *Panel::GetEffectiveTooltipText() const
{
	if ( _tooltipText )
	{
		return _tooltipText;
	}
	if ( m_pTooltips )
	{
		const char *result = m_pTooltips->GetText();
		if ( result )
		{
			return result;
		}
	}
	return "";
}

//-----------------------------------------------------------------------------
// Purpose: sets the proportional flag on this panel and all it's children
//-----------------------------------------------------------------------------
void Panel::SetProportional(bool state)
{ 
	// only do something if the state changes
	if( state != _flags.IsFlagSet( IS_PROPORTIONAL ) )
	{
		_flags.SetFlag( IS_PROPORTIONAL, state );	

		for(int i=0;i<GetChildCount();i++)
		{
			// recursively apply to all children
			GetChild(i)->SetProportional( IsProportional() );
		}
	}
	InvalidateLayout();
}


void Panel::SetKeyBoardInputEnabled( bool state )
{
	ipanel()->SetKeyBoardInputEnabled( GetVPanel(), state );
	for ( int i = 0; i < GetChildCount(); i++ )
	{
		Panel *child = GetChild( i );
		if ( !child )
		{
			continue;
		}
		child->SetKeyBoardInputEnabled( state );
	}

	// If turning off keyboard input enable, then make sure
	// this panel is not the current key focus of a parent panel
	if ( !state )
	{
		Panel *pParent = GetParent();
		if ( pParent )
		{
			if ( pParent->GetCurrentKeyFocus() == GetVPanel() )
			{
				pParent->RequestFocusNext();
			}
		}
	}
}

void Panel::SetMouseInputEnabled( bool state )
{
	ipanel()->SetMouseInputEnabled( GetVPanel(), state );
	/*	for(int i=0;i<GetChildCount();i++)
	{
	GetChild(i)->SetMouseInput(state);
	}*/
	vgui::surface()->CalculateMouseVisible();
}

bool Panel::IsKeyBoardInputEnabled()
{
	return ipanel()->IsKeyBoardInputEnabled( GetVPanel() );
}

bool Panel::IsMouseInputEnabled()
{
	return ipanel()->IsMouseInputEnabled( GetVPanel() );
}

class CFloatProperty : public vgui::IPanelAnimationPropertyConverter
{
public:
	virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		kv->SetFloat( entry->name(), *(float *)data );
	}
	
	virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		*(float *)data = kv->GetFloat( entry->name() );
	}

	virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		*(float *)data = atof( entry->defaultvalue() );
	}
};

class CProportionalFloatProperty : public vgui::IPanelAnimationPropertyConverter
{
public:
	virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		float f = *(float *)data;
		f = scheme()->GetProportionalNormalizedValueEx( panel->GetScheme(), f );
		kv->SetFloat( entry->name(), f );
	}
	
	virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		float f = kv->GetFloat( entry->name() );
		f = scheme()->GetProportionalScaledValueEx( panel->GetScheme(), f );
		*(float *)data = f;
	}

	virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		float f = atof( entry->defaultvalue() );
		f = scheme()->GetProportionalScaledValueEx( panel->GetScheme(), f );
		*(float *)data = f;
	}
};

class CIntProperty : public vgui::IPanelAnimationPropertyConverter
{
public:
	virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		kv->SetInt( entry->name(), *(int *)data );
	}
	
	virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		*(int *)data = kv->GetInt( entry->name() );
	}

	virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		*(int *)data = atoi( entry->defaultvalue() );
	}
};

class CProportionalIntProperty : public vgui::IPanelAnimationPropertyConverter
{
public:
	virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		int i = *(int *)data;
		i = scheme()->GetProportionalNormalizedValueEx( panel->GetScheme(), i );
		kv->SetInt( entry->name(), i );
	}
	
	virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		int i = kv->GetInt( entry->name() );
		i = scheme()->GetProportionalScaledValueEx( panel->GetScheme(), i );
		*(int *)data = i;
	}
	virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		int i = atoi( entry->defaultvalue() );
		i = scheme()->GetProportionalScaledValueEx( panel->GetScheme(), i );
		*(int *)data = i;
	}
};

class CProportionalIntWithScreenspacePropertyX : public vgui::IPanelAnimationPropertyConverter
{
public:
	int	ExtractValue( Panel *pPanel, const char *pszKey )
	{
		int nPos = 0;
		ComputePos( pPanel, pszKey, nPos, GetPanelDimension( pPanel ), GetScreenSize( pPanel ), true, OP_ADD );
		return nPos;
	}

	virtual int GetScreenSize( Panel *pPanel ) const
	{
		int nParentWide, nParentTall;
		if (pPanel->IsProportional() && pPanel->GetParent())
		{
			nParentWide = pPanel->GetParent()->GetWide();
			nParentTall = pPanel->GetParent()->GetTall();
		}
		else
		{
			surface()->GetScreenSize(nParentWide, nParentTall);
		}

		return nParentWide;
	}

	virtual int GetPanelDimension( Panel *pPanel ) const
	{
		return pPanel->GetWide();
	}

	virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		// Won't work with this, don't use it.
		Assert(0);
	}

	virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		*(int *)data = ExtractValue( panel, kv->GetString( entry->name() ) );
	}
	virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		*(int *)data = ExtractValue( panel, entry->defaultvalue() );
	}
};

class CProportionalIntWithScreenspacePropertyY : public CProportionalIntWithScreenspacePropertyX
{
public:
	virtual int GetScreenSize( Panel *pPanel ) const OVERRIDE
	{
		int nParentWide, nParentTall;
		if (pPanel->IsProportional() && pPanel->GetParent())
		{
			nParentWide = pPanel->GetParent()->GetWide();
			nParentTall = pPanel->GetParent()->GetTall();
		}
		else
		{
			surface()->GetScreenSize(nParentWide, nParentTall);
		}

		return nParentTall;
	}

	virtual int GetPanelDimension(Panel *pPanel) const OVERRIDE
	{
		return pPanel->GetTall();
	}
};

class CProportionalWidthProperty : public vgui::IPanelAnimationPropertyConverter
{
public:
	int	ExtractValue(Panel *pPanel, const char *pszKey)
	{
		if ( pszKey && ( pszKey[0] == 'o' || pszKey[0] == 'O' ) )
		{
			// We don't handle sizes based on the other dimension in this case
			Assert( 0 );
			return 0;
		}

		int nParentWide, nParentTall;
		if ( pPanel->IsProportional() && pPanel->GetParent() )
		{
			nParentWide = pPanel->GetParent()->GetWide();
			nParentTall = pPanel->GetParent()->GetTall();
		}
		else
		{
			surface()->GetScreenSize( nParentWide, nParentTall );
		}

		unsigned int nBuildFlags = 0;
		return Compute( pPanel, nBuildFlags, pszKey, nParentWide, nParentTall, false );
	}

	virtual void GetData(Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry)
	{
		// Won't work with this, don't use it.
		Assert(0);
	}

	virtual void SetData(Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry)
	{
		void *data = (void *)((*entry->m_pfnLookup)(panel));
		*(int *)data = ExtractValue(panel, kv->GetString(entry->name()));
	}
	virtual void InitFromDefault(Panel *panel, PanelAnimationMapEntry *entry)
	{
		void *data = (void *)((*entry->m_pfnLookup)(panel));
		*(int *)data = ExtractValue(panel, entry->defaultvalue());
	}

private:

	virtual int Compute( Panel* pPanel, unsigned int& nBuildFlags, const char *pszKey, int nParentWide, int nParentTall, bool bComputingOther )
	{
		KeyValuesAD kv( "temp" );
		kv->SetString( "wide", pszKey );

		return ComputeWide( pPanel, nBuildFlags, kv, nParentWide, nParentTall, false );
	}
};

class CProportionalHeightProperty : public CProportionalWidthProperty
{
private:
	virtual int Compute(Panel* pPanel, unsigned int& nBuildFlags, const char *pszKey, int nParentWide, int nParentTall, bool bComputingOther) OVERRIDE
	{
		KeyValuesAD kv( "temp" );
		kv->SetString( "tall", pszKey );

		return ComputeTall(pPanel, nBuildFlags, kv, nParentWide, nParentTall, false);
	}

};

class CColorProperty : public vgui::IPanelAnimationPropertyConverter
{
public:
	virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		kv->SetColor( entry->name(), *(Color *)data );
	}
	
	virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		vgui::IScheme *scheme = vgui::scheme()->GetIScheme( panel->GetScheme() );
		Assert( scheme );
		if ( scheme )
		{
			void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );

			char const *colorName = kv->GetString( entry->name() );
			if ( !colorName || !colorName[0] )
			{
				*(Color *)data = kv->GetColor( entry->name() );
			}
			else
			{
				*(Color *)data = scheme->GetColor( colorName, Color( 0, 0, 0, 0 ) );
			}
		}
	}

	virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry )
	{
		vgui::IScheme *scheme = vgui::scheme()->GetIScheme( panel->GetScheme() );
		Assert( scheme );
		if ( scheme )
		{
			void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
			*(Color *)data = scheme->GetColor( entry->defaultvalue(), Color( 0, 0, 0, 0 ) );
		}
	}
};

class CBoolProperty : public vgui::IPanelAnimationPropertyConverter
{
public:
	virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		kv->SetInt( entry->name(), *(bool *)data ? 1 : 0 );
	}
	
	virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		*(bool *)data = kv->GetInt( entry->name() ) ? true : false;
	}

	virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		bool b = false;
		if ( !stricmp( entry->defaultvalue(), "true" )||
			atoi( entry->defaultvalue() )!= 0 )
		{
			b = true;
		}

		*(bool *)data = b;
	}
};

class CStringProperty : public vgui::IPanelAnimationPropertyConverter
{
public:
	virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		kv->SetString( entry->name(), (char *)data );
	}
	
	virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		strcpy( (char *)data, kv->GetString( entry->name() ) );
	}

	virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		strcpy( ( char * )data, entry->defaultvalue() );
	}
};

class CHFontProperty : public vgui::IPanelAnimationPropertyConverter
{
public:
	virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		vgui::IScheme *scheme = vgui::scheme()->GetIScheme( panel->GetScheme() );
		Assert( scheme );
		if ( scheme )
		{
			void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
			char const *fontName = scheme->GetFontName( *(HFont *)data );
			kv->SetString( entry->name(), fontName );
		}
	}
	
	virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		vgui::IScheme *scheme = vgui::scheme()->GetIScheme( panel->GetScheme() );
		Assert( scheme );
		if ( scheme )
		{
			void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
			char const *fontName = kv->GetString( entry->name() );
			*(HFont *)data = scheme->GetFont( fontName, panel->IsProportional() );
		}
	}

	virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry )
	{
		vgui::IScheme *scheme = vgui::scheme()->GetIScheme( panel->GetScheme() );
		Assert( scheme );
		if ( scheme )
		{
			void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
			*(HFont *)data = scheme->GetFont( entry->defaultvalue(), panel->IsProportional() );
		}
	}
};

class CTextureIdProperty : public vgui::IPanelAnimationPropertyConverter
{
public:
	virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
		int currentId = *(int *)data;

		// lookup texture name for id
		char texturename[ 512 ];
		if ( currentId != -1 &&
			surface()->DrawGetTextureFile( currentId, texturename, sizeof( texturename ) ) )
		{
			kv->SetString( entry->name(), texturename );
		}
		else
		{
			kv->SetString( entry->name(), "" );
		}
	}
	
	virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );

		int currentId = -1;

		char const *texturename = kv->GetString( entry->name() );
		if ( texturename && texturename[ 0 ] )
		{
			currentId = surface()->DrawGetTextureId( texturename );
			if ( currentId == -1 )
			{
				currentId = surface()->CreateNewTextureID();
			}
			surface()->DrawSetTextureFile( currentId, texturename, false, true );
		}

		*(int *)data = currentId;
	}

	virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry )
	{
		void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );

		int currentId = -1;

		char const *texturename = entry->defaultvalue();
		if ( texturename && texturename[ 0 ] )
		{
			currentId = surface()->DrawGetTextureId( texturename );
			if ( currentId == -1 )
			{
				currentId = surface()->CreateNewTextureID();
			}
			surface()->DrawSetTextureFile( currentId, texturename, false, true );
		}

		*(int *)data = currentId;
	}
};

static CFloatProperty floatconverter;
static CProportionalFloatProperty p_floatconverter;
static CIntProperty intconverter;
static CProportionalIntProperty p_intconverter;
static CProportionalIntWithScreenspacePropertyX p_screenspace_intconverter_X;
static CProportionalIntWithScreenspacePropertyY p_screenspace_intconverter_Y;
static CColorProperty colorconverter;
static CBoolProperty boolconverter;
static CStringProperty stringconverter;
static CHFontProperty fontconverter;
static CTextureIdProperty textureidconverter;
static CProportionalWidthProperty proportional_width_converter;
static CProportionalHeightProperty proportional_height_converter;
//static CProportionalXPosProperty xposconverter;
//static CProportionalYPosProperty yposconverter;

static CUtlDict< IPanelAnimationPropertyConverter *, int > g_AnimationPropertyConverters;

static IPanelAnimationPropertyConverter *FindConverter( char const *typeName )
{
	int lookup = g_AnimationPropertyConverters.Find( typeName );
	if ( lookup == g_AnimationPropertyConverters.InvalidIndex() )
		return NULL;

	IPanelAnimationPropertyConverter *converter = g_AnimationPropertyConverters[ lookup ];
	return converter;
}

void Panel::AddPropertyConverter( char const *typeName, IPanelAnimationPropertyConverter *converter )
{
	int lookup = g_AnimationPropertyConverters.Find( typeName );
	if ( lookup != g_AnimationPropertyConverters.InvalidIndex() )
	{
		Msg( "Already have converter for type %s, ignoring...\n", typeName );
		return;
	}

	g_AnimationPropertyConverters.Insert( typeName, converter );
}

//-----------------------------------------------------------------------------
// Purpose: Static method to initialize all needed converters
//-----------------------------------------------------------------------------
void Panel::InitPropertyConverters( void )
{
	static bool initialized = false;
	if ( initialized )
		return;
	initialized = true;

	AddPropertyConverter( "float", &floatconverter );
	AddPropertyConverter( "int", &intconverter );
	AddPropertyConverter( "Color", &colorconverter );
	//AddPropertyConverter( "vgui::Color", &colorconverter );
	AddPropertyConverter( "bool", &boolconverter );
	AddPropertyConverter( "char", &stringconverter );
	AddPropertyConverter( "string", &stringconverter );
	AddPropertyConverter( "HFont", &fontconverter );
	AddPropertyConverter( "vgui::HFont", &fontconverter );

	// This is an aliased type for proportional float
	AddPropertyConverter( "proportional_float", &p_floatconverter );
	AddPropertyConverter( "proportional_int", &p_intconverter );

	AddPropertyConverter( "proportional_xpos", &p_screenspace_intconverter_X );
	AddPropertyConverter( "proportional_ypos", &p_screenspace_intconverter_Y );

	AddPropertyConverter( "proportional_width", &proportional_width_converter );
	AddPropertyConverter( "proportional_height", &proportional_height_converter );

	AddPropertyConverter( "textureid", &textureidconverter );
}

bool Panel::InternalRequestInfo( PanelAnimationMap *map, KeyValues *outputData )
{
	if ( !map )
		return false;

	Assert( outputData );

	char const *name = outputData->GetName();

	PanelAnimationMapEntry *e = FindPanelAnimationEntry( name, map );
	if ( e )
	{
		IPanelAnimationPropertyConverter *converter = FindConverter( e->type() );
		if ( converter )
		{
			converter->GetData( this, outputData, e );
			return true;
		}
	}

	return false;
}

bool Panel::InternalSetInfo( PanelAnimationMap *map, KeyValues *inputData )
{
	if ( !map )
		return false;

	Assert( inputData );

	char const *name = inputData->GetName();

	PanelAnimationMapEntry *e = FindPanelAnimationEntry( name, map );
	if ( e )
	{
		IPanelAnimationPropertyConverter *converter = FindConverter( e->type() );
		if ( converter )
		{
			converter->SetData( this, inputData, e );
			return true;
		}
	}

	return false;
}

PanelAnimationMapEntry *Panel::FindPanelAnimationEntry( char const *scriptname, PanelAnimationMap *map )
{
	if ( !map )
		return NULL;

	Assert( scriptname );

	// Look through mapping for entry
	int c = map->entries.Count();
	for ( int i = 0; i < c; i++ )
	{
		PanelAnimationMapEntry *e = &map->entries[ i ];

		if ( !stricmp( e->name(), scriptname ) )
		{
			return e;
		}
	}

	// Recurse
	if ( map->baseMap )
	{
		return FindPanelAnimationEntry( scriptname, map->baseMap );
	}

	return NULL;
}

// Recursively invoke settings for PanelAnimationVars
void Panel::InternalApplySettings( PanelAnimationMap *map, KeyValues *inResourceData)
{
	tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s", __FUNCTION__, GetName() );

	// Loop through keys
	KeyValues *kv;
	
	for ( kv = inResourceData->GetFirstSubKey(); kv; kv = kv->GetNextKey() )
	{
		char const *varname = kv->GetName();

		PanelAnimationMapEntry *entry = FindPanelAnimationEntry( varname, GetAnimMap() );
		if ( entry )
		{
			// Set value to value from script
			IPanelAnimationPropertyConverter *converter = FindConverter( entry->type() );
			if ( converter )
			{
				converter->SetData( this, inResourceData, entry );
			}
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: sets the default values of all CPanelAnimationVars
//-----------------------------------------------------------------------------
void  Panel::InternalInitDefaultValues( PanelAnimationMap *map )
{
	_flags.ClearFlag( NEEDS_DEFAULT_SETTINGS_APPLIED );

	// Look through mapping for entry
	int c = map->entries.Count();
	for ( int i = 0; i < c; i++ )
	{
		PanelAnimationMapEntry *e = &map->entries[ i ];
		Assert( e );
		IPanelAnimationPropertyConverter *converter = FindConverter( e->type() );
		if ( !converter )
			continue;

		converter->InitFromDefault( this, e );
	}

	if ( map->baseMap )
	{	
		InternalInitDefaultValues( map->baseMap );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
//-----------------------------------------------------------------------------
int	Panel::GetPaintBackgroundType()
{
	return m_nPaintBackgroundType;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : w - 
//			h - 
//-----------------------------------------------------------------------------
void Panel::GetCornerTextureSize( int& w, int& h )
{
	if ( m_nBgTextureId1 == -1 )
	{
		w = h = 0;
		return;
	}
	surface()->DrawGetTextureSize(m_nBgTextureId1, w, h);
}

//-----------------------------------------------------------------------------
// Purpose: draws a selection box
//-----------------------------------------------------------------------------
void Panel::DrawBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha, bool hollow /*=false*/ )
{
	if ( m_nBgTextureId1 == -1 ||
		 m_nBgTextureId2 == -1 ||
		 m_nBgTextureId3 == -1 ||
		 m_nBgTextureId4 == -1 )
	{
		return;
	}

	color[3] *= normalizedAlpha;

	// work out our bounds
	int cornerWide, cornerTall;
	GetCornerTextureSize( cornerWide, cornerTall );

	// draw the background in the areas not occupied by the corners
	// draw it in three horizontal strips
	surface()->DrawSetColor(color);
	surface()->DrawFilledRect(x + cornerWide, y, x + wide - cornerWide,	y + cornerTall);
	if ( !hollow )
	{
		surface()->DrawFilledRect(x, y + cornerTall, x + wide, y + tall - cornerTall);
	}
	else
	{
		surface()->DrawFilledRect(x, y + cornerTall, x + cornerWide, y + tall - cornerTall);
		surface()->DrawFilledRect(x + wide - cornerWide, y + cornerTall, x + wide, y + tall - cornerTall);
	}
	surface()->DrawFilledRect(x + cornerWide, y + tall - cornerTall, x + wide - cornerWide, y + tall);

	// draw the corners

	//=============================================================================
	// HPE_BEGIN:
	// [tj] We now check each individual corner and decide whether to draw it straight or rounded
	//=============================================================================
	//TOP-LEFT
	if (ShouldDrawTopLeftCornerRounded())
	{
		surface()->DrawSetTexture(m_nBgTextureId1);
		surface()->DrawTexturedRect(x, y, x + cornerWide, y + cornerTall);
	}
	else
	{
		surface()->DrawFilledRect(x, y, x + cornerWide, y + cornerTall);
	}


	//TOP-RIGHT
	if (ShouldDrawTopRightCornerRounded())
	{
		surface()->DrawSetTexture(m_nBgTextureId2);
		surface()->DrawTexturedRect(x + wide - cornerWide, y, x + wide, y + cornerTall);
	}
	else
	{
		surface()->DrawFilledRect(x + wide - cornerWide, y, x + wide, y + cornerTall);
	}

	//BOTTOM-LEFT
	if (ShouldDrawBottomLeftCornerRounded())
	{
		surface()->DrawSetTexture(m_nBgTextureId4);
		surface()->DrawTexturedRect(x + 0, y + tall - cornerTall, x + cornerWide, y + tall);
	}
	else
	{
		surface()->DrawFilledRect(x + 0, y + tall - cornerTall, x + cornerWide, y + tall);
	}


	//BOTTOM-RIGHT
	if (ShouldDrawBottomRightCornerRounded())
	{
		surface()->DrawSetTexture(m_nBgTextureId3);
		surface()->DrawTexturedRect(x + wide - cornerWide, y + tall - cornerTall, x + wide, y + tall);
	}
	else
	{
		surface()->DrawFilledRect(x + wide - cornerWide, y + tall - cornerTall, x + wide, y + tall);
	}
	//=============================================================================
	// HPE_END
	//=============================================================================
}

void Panel::DrawBoxFade(int x, int y, int wide, int tall, Color color, float normalizedAlpha, unsigned int alpha0, unsigned int alpha1, bool bHorizontal, bool hollow /*=false*/ )
{
	if ( m_nBgTextureId1 == -1 ||
		m_nBgTextureId2 == -1 ||
		m_nBgTextureId3 == -1 ||
		m_nBgTextureId4 == -1 ||
		surface()->DrawGetAlphaMultiplier() == 0 )
	{
		return;
	}

	color[3] *= normalizedAlpha;

	// work out our bounds
	int cornerWide, cornerTall;
	GetCornerTextureSize( cornerWide, cornerTall );

	if ( !bHorizontal )
	{
		// draw the background in the areas not occupied by the corners
		// draw it in three horizontal strips
		surface()->DrawSetColor(color);
		surface()->DrawFilledRectFade(x + cornerWide, y, x + wide - cornerWide,	y + cornerTall, alpha0, alpha0, bHorizontal );
		if ( !hollow )
		{
			surface()->DrawFilledRectFade(x, y + cornerTall, x + wide, y + tall - cornerTall, alpha0, alpha1, bHorizontal);
		}
		else
		{
			surface()->DrawFilledRectFade(x, y + cornerTall, x + cornerWide, y + tall - cornerTall, alpha0, alpha1, bHorizontal);
			surface()->DrawFilledRectFade(x + wide - cornerWide, y + cornerTall, x + wide, y + tall - cornerTall, alpha0, alpha1, bHorizontal);
		}
		surface()->DrawFilledRectFade(x + cornerWide, y + tall - cornerTall, x + wide - cornerWide, y + tall, alpha1, alpha1, bHorizontal);
	}
	else
	{
		// draw the background in the areas not occupied by the corners
		// draw it in three horizontal strips
		surface()->DrawSetColor(color);
		surface()->DrawFilledRectFade(x, y + cornerTall, x + cornerWide, y + tall - cornerTall, alpha0, alpha0, bHorizontal );
		if ( !hollow )
		{
			surface()->DrawFilledRectFade(x + cornerWide, y, x + wide - cornerWide, y + tall, alpha0, alpha1, bHorizontal);
		}
		else
		{
			// FIXME: Hollow horz version not implemented
			//surface()->DrawFilledRectFade(x, y + cornerTall, x + cornerWide, y + tall - cornerTall, alpha0, alpha1, bHorizontal);
			//surface()->DrawFilledRectFade(x + wide - cornerWide, y + cornerTall, x + wide, y + tall - cornerTall, alpha0, alpha1, bHorizontal);
		}
		surface()->DrawFilledRectFade(x + wide - cornerWide, y + cornerTall, x + wide, y + tall - cornerTall, alpha1, alpha1, bHorizontal);
	}

	float fOldAlpha = color[ 3 ];
	int iAlpha0 = fOldAlpha * ( static_cast<float>( alpha0 ) / 255.0f );
	int iAlpha1 = fOldAlpha * ( static_cast<float>( alpha1 ) / 255.0f );

	// draw the corners
	if ( !bHorizontal )
	{
		color[ 3 ] = iAlpha0;
		surface()->DrawSetColor( color );
		surface()->DrawSetTexture(m_nBgTextureId1);
		surface()->DrawTexturedRect(x, y, x + cornerWide, y + cornerTall);
		surface()->DrawSetTexture(m_nBgTextureId2);
		surface()->DrawTexturedRect(x + wide - cornerWide, y, x + wide, y + cornerTall);

		color[ 3 ] = iAlpha1;
		surface()->DrawSetColor( color );
		surface()->DrawSetTexture(m_nBgTextureId3);
		surface()->DrawTexturedRect(x + wide - cornerWide, y + tall - cornerTall, x + wide, y + tall);
		surface()->DrawSetTexture(m_nBgTextureId4);
		surface()->DrawTexturedRect(x + 0, y + tall - cornerTall, x + cornerWide, y + tall);
	}
	else
	{
		color[ 3 ] = iAlpha0;
		surface()->DrawSetColor( color );
		surface()->DrawSetTexture(m_nBgTextureId1);
		surface()->DrawTexturedRect(x, y, x + cornerWide, y + cornerTall);
		surface()->DrawSetTexture(m_nBgTextureId4);
		surface()->DrawTexturedRect(x + 0, y + tall - cornerTall, x + cornerWide, y + tall);

		color[ 3 ] = iAlpha1;
		surface()->DrawSetColor( color );
		surface()->DrawSetTexture(m_nBgTextureId2);
		surface()->DrawTexturedRect(x + wide - cornerWide, y, x + wide, y + cornerTall);
		surface()->DrawSetTexture(m_nBgTextureId3);
		surface()->DrawTexturedRect(x + wide - cornerWide, y + tall - cornerTall, x + wide, y + tall);
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : x - 
//			y - 
//			wide - 
//			tall - 
//			color - 
//			normalizedAlpha - 
//-----------------------------------------------------------------------------
void Panel::DrawHollowBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha )
{
	DrawBox( x, y, wide, tall, color, normalizedAlpha, true );
}

//=============================================================================
// HPE_BEGIN:
// [menglish] Draws a hollow box similar to the already existing draw hollow box function, but takes the indents as params
//=============================================================================

void Panel::DrawHollowBox( int x, int y, int wide, int tall, Color color, float normalizedAlpha, int cornerWide, int cornerTall )
{
	if ( m_nBgTextureId1 == -1 ||
		m_nBgTextureId2 == -1 ||
		m_nBgTextureId3 == -1 ||
		m_nBgTextureId4 == -1 )
	{
		return;
	}

	color[3] *= normalizedAlpha;

	// draw the background in the areas not occupied by the corners
	// draw it in three horizontal strips
	surface()->DrawSetColor(color);
	surface()->DrawFilledRect(x + cornerWide, y, x + wide - cornerWide,	y + cornerTall);
	surface()->DrawFilledRect(x, y + cornerTall, x + cornerWide, y + tall - cornerTall);
	surface()->DrawFilledRect(x + wide - cornerWide, y + cornerTall, x + wide, y + tall - cornerTall);
	surface()->DrawFilledRect(x + cornerWide, y + tall - cornerTall, x + wide - cornerWide, y + tall);

	// draw the corners
	surface()->DrawSetTexture(m_nBgTextureId1);
	surface()->DrawTexturedRect(x, y, x + cornerWide, y + cornerTall);
	surface()->DrawSetTexture(m_nBgTextureId2);
	surface()->DrawTexturedRect(x + wide - cornerWide, y, x + wide, y + cornerTall);
	surface()->DrawSetTexture(m_nBgTextureId3);
	surface()->DrawTexturedRect(x + wide - cornerWide, y + tall - cornerTall, x + wide, y + tall);
	surface()->DrawSetTexture(m_nBgTextureId4);
	surface()->DrawTexturedRect(x + 0, y + tall - cornerTall, x + cornerWide, y + tall);
}

//=============================================================================
// HPE_END
//=============================================================================

//-----------------------------------------------------------------------------
// Purpose: draws a selection box
//-----------------------------------------------------------------------------
void Panel::DrawTexturedBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha )
{
	if ( m_nBgTextureId1 == -1 )
		return;

	color[3] *= normalizedAlpha;

	surface()->DrawSetColor( color );
	surface()->DrawSetTexture(m_nBgTextureId1);
	surface()->DrawTexturedRect(x, y, x + wide, y + tall);
}

//-----------------------------------------------------------------------------
// Purpose: Marks this panel as draggable (note that children will chain to their parents to see if any parent is draggable)
// Input  : enabled - 
//-----------------------------------------------------------------------------
void Panel::SetDragEnabled( bool enabled )
{
#if defined( VGUI_USEDRAGDROP )
	// If turning it off, quit dragging if mid-drag
	if ( !enabled && 
		m_pDragDrop->m_bDragging )
	{
		OnFinishDragging( false, (MouseCode)-1 );
	}
	m_pDragDrop->m_bDragEnabled = enabled;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool Panel::IsDragEnabled() const
{
#if defined( VGUI_USEDRAGDROP )
	return m_pDragDrop->m_bDragEnabled;
#endif
	return false;
}

void Panel::SetShowDragHelper( bool enabled )
{
#if defined( VGUI_USEDRAGDROP )
	m_pDragDrop->m_bShowDragHelper = enabled;
#endif
}

// Use this to prevent chaining up from a parent which can mess with mouse functionality if you don't want to chain up from a child panel to the best
//  draggable parent.
void Panel::SetBlockDragChaining( bool block )
{
#if defined( VGUI_USEDRAGDROP )
	m_pDragDrop->m_bPreventChaining = block;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool Panel::IsBlockingDragChaining() const
{
#if defined( VGUI_USEDRAGDROP )
	return m_pDragDrop->m_bPreventChaining;
#endif
	return true;
}


//-----------------------------------------------------------------------------
// accessors for m_nDragStartTolerance
//-----------------------------------------------------------------------------
int Panel::GetDragStartTolerance() const
{
#if defined( VGUI_USEDRAGDROP )
	return m_pDragDrop->m_nDragStartTolerance;
#endif
	return 0;
}

void Panel::SetDragSTartTolerance( int nTolerance )
{
#if defined( VGUI_USEDRAGDROP )
	m_pDragDrop->m_nDragStartTolerance = nTolerance;
#endif
}


//-----------------------------------------------------------------------------
// Purpose: Marks this panel as droppable ( note that children will chain to their parents to see if any parent is droppable)
// Input  : enabled - 
//-----------------------------------------------------------------------------
void Panel::SetDropEnabled( bool enabled, float flHoverContextTime /* = 0.0f */ )
{
#if defined( VGUI_USEDRAGDROP )
	m_pDragDrop->m_bDropEnabled = enabled;
	m_pDragDrop->m_flHoverContextTime = flHoverContextTime;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool Panel::IsDropEnabled() const
{
#if defined( VGUI_USEDRAGDROP )
	return m_pDragDrop->m_bDropEnabled;
#endif
	return false;
}

//-----------------------------------------------------------------------------
// Purpose: Chains up to any parent 
// 1) marked DropEnabled; and 
// 2) willing to accept the drop payload
// Input  :  - 
// Output : Panel
//-----------------------------------------------------------------------------
Panel *Panel::GetDropTarget( CUtlVector< KeyValues * >& msglist )
{
#if defined( VGUI_USEDRAGDROP )
	// Found one
	if ( m_pDragDrop->m_bDropEnabled && 
		IsDroppable( msglist ) )
	{
		return this;
	}

	// Chain up
	if ( GetParent() )
	{
		return GetParent()->GetDropTarget( msglist );
	}
#endif
	// No luck
	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose: Chains up to first parent marked DragEnabled
// Input  :  - 
// Output : Panel
//-----------------------------------------------------------------------------
Panel *Panel::GetDragPanel()
{
#if defined( VGUI_USEDRAGDROP )
	// If we encounter a blocker, stop chaining
	if ( m_pDragDrop->m_bPreventChaining )
		return NULL;

	if ( m_pDragDrop->m_bDragEnabled )
		return this;

	// Chain up
	if ( GetParent() )
	{
		return GetParent()->GetDragPanel();
	}
#endif
	// No luck
	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
//-----------------------------------------------------------------------------
void Panel::OnStartDragging()
{
#if defined( VGUI_USEDRAGDROP )
	// Only left mouse initiates drag/drop.
	// FIXME: Revisit?
	if ( !input()->IsMouseDown( MOUSE_LEFT ) )
		return;

	if ( !m_pDragDrop->m_bDragEnabled )
		return;

	if ( m_pDragDrop->m_bDragging )
		return;

	g_DragDropCapture = this;

	m_pDragDrop->m_bDragStarted = false;
	m_pDragDrop->m_bDragging = true;
	input()->GetCursorPos( m_pDragDrop->m_nStartPos[ 0 ], m_pDragDrop->m_nStartPos[ 1 ] );
	m_pDragDrop->m_nLastPos[ 0 ] = m_pDragDrop->m_nStartPos[ 0 ];
	m_pDragDrop->m_nLastPos[ 1 ] = m_pDragDrop->m_nStartPos[ 1 ];

	OnContinueDragging();
#endif
}

//-----------------------------------------------------------------------------
// Purpose: Called if drag drop is started but not dropped on top of droppable panel...
// Input  :  - 
//-----------------------------------------------------------------------------
void Panel::OnDragFailed( CUtlVector< KeyValues * >& msglist )
{
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
//-----------------------------------------------------------------------------
void Panel::OnFinishDragging( bool mousereleased, MouseCode code, bool abort /*= false*/ )
{
#if defined( VGUI_USEDRAGDROP )
	g_DragDropCapture = NULL;

	if ( !m_pDragDrop->m_bDragEnabled )
		return;

	Assert( m_pDragDrop->m_bDragging );

	if ( !m_pDragDrop->m_bDragging )
		return;

	int x, y;
	input()->GetCursorPos( x, y );

    m_pDragDrop->m_nLastPos[ 0 ] = x;
	m_pDragDrop->m_nLastPos[ 1 ] = y;

	if ( s_DragDropHelper.Get() )
	{
		s_DragDropHelper->RemovePanel( this );
	}

	m_pDragDrop->m_bDragging = false;

	CUtlVector< KeyValues * >& data = m_pDragDrop->m_DragData;
	int nData = data.Count();

	Panel *target = NULL;
	bool shouldDrop = false;

	if ( m_pDragDrop->m_bDragStarted )
	{
		char cmd[ 256 ];
		Q_strncpy( cmd, "default", sizeof( cmd ) );

		if ( mousereleased &&
			m_pDragDrop->m_hCurrentDrop != 0 &&
			m_pDragDrop->m_hDropContextMenu.Get() )
		{
			Menu *menu = m_pDragDrop->m_hDropContextMenu;

			VPANEL hover = menu->IsWithinTraverse( x, y, false );
			if ( hover )
			{
				Panel *pHover = ipanel()->GetPanel( hover, GetModuleName() );
				if ( pHover )
				{
					// Figure out if it's a menu item...
					int c = menu->GetItemCount();
					for ( int i = 0; i < c; ++i )
					{
						int id = menu->GetMenuID( i );
						MenuItem *item = menu->GetMenuItem( id );
						if ( item == pHover )
						{
							KeyValues *command = item->GetCommand();
							if ( command )
							{
								char const *p = command->GetString( "command", "" );
								if ( p && p[ 0 ] )
								{
									Q_strncpy( cmd, p, sizeof( cmd ) );
								}
							}
						}
					}
				}
			}

			delete menu;
			m_pDragDrop->m_hDropContextMenu = NULL;
		}

		for ( int i = 0 ; i < nData; ++i )
		{
			KeyValues *msg = data[ i ];

			msg->SetString( "command", cmd );

			msg->SetInt( "screenx", x );
			msg->SetInt( "screeny", y );
		}

		target = m_pDragDrop->m_hCurrentDrop.Get();
		if ( target && !abort )
		{
			int localmousex = x, localmousey = y;
			// Convert screen space coordintes to coordinates relative to drop window
			target->ScreenToLocal( localmousex, localmousey );

			for ( int i = 0 ; i < nData; ++i )
			{
				KeyValues *msg = data[ i ];

				msg->SetInt( "x", localmousex );
				msg->SetInt( "y", localmousey );
			}

			shouldDrop = true;
		}

		if ( !shouldDrop )
		{
			OnDragFailed( data );
		}
	}

	m_pDragDrop->m_bDragStarted = false;
	m_pDragDrop->m_DragPanels.RemoveAll();
	m_pDragDrop->m_hCurrentDrop = NULL;

	// Copy data ptrs out of data because OnPanelDropped might cause this panel to be deleted
	// and our this ptr will be hosed...
	CUtlVector< KeyValues * > temp;
	for ( int i = 0 ; i < nData; ++i )
	{
		temp.AddToTail( data[ i ] );
	}
	data.RemoveAll();

	if ( shouldDrop && target )
	{
		target->OnPanelDropped( temp );
	}
	for ( int i = 0 ; i < nData; ++i )
	{
        temp[ i ]->deleteThis();
	}
#endif
}

void Panel::OnDropContextHoverShow( CUtlVector< KeyValues * >& msglist )
{
}

void Panel::OnDropContextHoverHide( CUtlVector< KeyValues * >& msglist )
{
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *msg - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool Panel::IsDroppable( CUtlVector< KeyValues * >& msglist )
{
	return false;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : startx - 
//			starty - 
//			mx - 
//			my - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool Panel::CanStartDragging( int startx, int starty, int mx, int my )
{
#if defined( VGUI_USEDRAGDROP )
	if ( IsStartDragWhenMouseExitsPanel() )
	{
		ScreenToLocal( mx, my );
		if ( mx < 0 || my < 0 )
			return true;
		if ( mx > GetWide() || my > GetTall() )
			return true;

		return false;
	}

	int deltax = abs( mx - startx );
	int deltay = abs( my - starty );
	if ( deltax > m_pDragDrop->m_nDragStartTolerance ||
		 deltay > m_pDragDrop->m_nDragStartTolerance )
	{
		return true;
	}
#endif
	return false;
}

HCursor Panel::GetDropCursor( CUtlVector< KeyValues * >& msglist )
{
	return dc_arrow;
}

bool IsSelfDroppable( CUtlVector< KeyValues * > &dragData )
{
	if ( dragData.Count() == 0 )
		return false;

	KeyValues *pKeyValues( dragData[ 0 ] );
	if ( !pKeyValues )
		return false;

	return pKeyValues->GetInt( "selfDroppable" ) != 0;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
//-----------------------------------------------------------------------------
void Panel::OnContinueDragging()
{
#if defined( VGUI_USEDRAGDROP )
	if ( !m_pDragDrop->m_bDragEnabled )
		return;

	if ( !m_pDragDrop->m_bDragging )
		return;

	int x, y;
	input()->GetCursorPos( x, y );

	// Update last position
	m_pDragDrop->m_nLastPos[ 0 ] = x;
	m_pDragDrop->m_nLastPos[ 1 ] = y;

	if ( !m_pDragDrop->m_bDragStarted )
	{
		if ( CanStartDragging( m_pDragDrop->m_nStartPos[ 0 ], m_pDragDrop->m_nStartPos[ 1 ], x, y ) )
		{
			m_pDragDrop->m_bDragStarted = true;
			CreateDragData();
		}
		else
		{
			return;
		}
	}

	if ( !s_DragDropHelper.Get() && m_pDragDrop->m_bShowDragHelper )
	{
		s_DragDropHelper = new CDragDropHelperPanel();
		s_DragDropHelper->SetKeyBoardInputEnabled( false );
		s_DragDropHelper->SetMouseInputEnabled( false );
		Assert( s_DragDropHelper.Get() );
	}

	if ( !s_DragDropHelper.Get() )
		return;

	s_DragDropHelper->AddPanel( this );

	Assert( m_pDragDrop->m_DragData.Count() );

	vgui::PHandle oldDrop = m_pDragDrop->m_hCurrentDrop;

	// See what's under that
	m_pDragDrop->m_hCurrentDrop = NULL;

	// Search under mouse pos...
	Panel *dropTarget = FindDropTargetPanel();
	if ( dropTarget )
	{
		dropTarget = dropTarget->GetDropTarget( m_pDragDrop->m_DragData );
	}

	// it's not okay until we find a droppable panel
	surface()->SetCursor( dc_no );

	if ( dropTarget )
	{
		if ( dropTarget != this || IsSelfDroppable( m_pDragDrop->m_DragData ) )
		{
			m_pDragDrop->m_hCurrentDrop = dropTarget;
			surface()->SetCursor( dropTarget->GetDropCursor( m_pDragDrop->m_DragData ) );
		}
	}

	if ( m_pDragDrop->m_hCurrentDrop.Get() != oldDrop.Get() )
	{
		if ( oldDrop.Get() )
		{
			oldDrop->OnPanelExitedDroppablePanel( m_pDragDrop->m_DragData );
		}

		if ( m_pDragDrop->m_hCurrentDrop.Get() )
		{
			m_pDragDrop->m_hCurrentDrop->OnPanelEnteredDroppablePanel( m_pDragDrop->m_DragData );
			m_pDragDrop->m_hCurrentDrop->OnDropContextHoverHide( m_pDragDrop->m_DragData );

			// Reset hover time
			m_pDragDrop->m_lDropHoverTime = system()->GetTimeMillis();
			m_pDragDrop->m_bDropMenuShown = false;
		}

		// Discard any stale context menu...
		if ( m_pDragDrop->m_hDropContextMenu.Get() )
		{
			delete m_pDragDrop->m_hDropContextMenu.Get();
		}
	}

	if ( m_pDragDrop->m_hCurrentDrop != 0 &&
		m_pDragDrop->m_hDropContextMenu.Get() )
	{
		Menu *menu = m_pDragDrop->m_hDropContextMenu;

		VPANEL hover = menu->IsWithinTraverse( x, y, false );
		if ( hover )
		{
			Panel *pHover = ipanel()->GetPanel( hover, GetModuleName() );
			if ( pHover )
			{
				// Figure out if it's a menu item...
				int c = menu->GetItemCount();
				for ( int i = 0; i < c; ++i )
				{
					int id = menu->GetMenuID( i );
					MenuItem *item = menu->GetMenuItem( id );
					if ( item == pHover )
					{
						menu->SetCurrentlyHighlightedItem( id );
					}
				}
			}
		}
		else
		{
			menu->ClearCurrentlyHighlightedItem();
		}
	}
#endif
}

#if defined( VGUI_USEDRAGDROP )
//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
// Output : DragDrop_t
//-----------------------------------------------------------------------------
DragDrop_t *Panel::GetDragDropInfo()
{
	Assert( m_pDragDrop );
	return m_pDragDrop;
}
#endif

void Panel::OnGetAdditionalDragPanels( CUtlVector< Panel * >& dragabbles )
{
	// Nothing here
}

//-----------------------------------------------------------------------------
// Purpose: Virtual method to allow panels to add to the default values
// Input  : *msg - 
//-----------------------------------------------------------------------------
void Panel::OnCreateDragData( KeyValues *msg )
{
	// These values are filled in for you:
	// "panel"	ptr to panel being dropped
	// "screenx", "screeny" - drop cursor pos in screen space
	// "x", "y" - drop coordinates relative to this window (the window being dropped upon)
}

// Called if m_flHoverContextTime was non-zero, allows droppee to preview the drop data and show an appropriate menu
bool Panel::GetDropContextMenu( Menu *menu, CUtlVector< KeyValues * >& msglist )
{
	return false;
}

void Panel::CreateDragData()
{
#if defined( VGUI_USEDRAGDROP )
	int i, c;

	if ( m_pDragDrop->m_DragData.Count() )
	{
		return;
	}

	PHandle h;
	h = this;
	m_pDragDrop->m_DragPanels.AddToTail( h );

	CUtlVector< Panel * > temp;
	OnGetAdditionalDragPanels( temp );
	c = temp.Count();
	for ( i = 0; i < c; ++i )
	{
		h = temp[ i ];
		m_pDragDrop->m_DragPanels.AddToTail( h );
	}

	c = m_pDragDrop->m_DragPanels.Count();
	for ( i = 0 ; i < c; ++i )
	{
		Panel *sibling = m_pDragDrop->m_DragPanels[ i ].Get();
		if ( !sibling )
		{
			continue;
		}

		KeyValues *msg = new KeyValues( "DragDrop" );
		msg->SetPtr( "panel", sibling );

		sibling->OnCreateDragData( msg );

		m_pDragDrop->m_DragData.AddToTail( msg );
	}
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
// Output : KeyValues
//-----------------------------------------------------------------------------
void Panel::GetDragData( CUtlVector< KeyValues * >& list )
{
#if defined( VGUI_USEDRAGDROP )
	int i, c;

	list.RemoveAll();

	c = m_pDragDrop->m_DragData.Count();
	for ( i = 0 ; i < c; ++i )
	{
		list.AddToTail( m_pDragDrop->m_DragData[ i ] );
	}
#endif
}

#if defined( VGUI_USEDRAGDROP )
CDragDropHelperPanel::CDragDropHelperPanel() : BaseClass( NULL, "DragDropHelper" )
{
	SetVisible( true );
	SetPaintEnabled( false );
	SetPaintBackgroundEnabled( false );
	SetMouseInputEnabled( false );
	SetKeyBoardInputEnabled( false );
	// SetCursor( dc_none );
	ipanel()->SetTopmostPopup( GetVPanel(), true );
	int w, h;
	surface()->GetScreenSize( w, h );
	SetBounds( 0, 0, w, h );

	SetPostChildPaintEnabled( true );

	MakePopup( false );
}

VPANEL CDragDropHelperPanel::IsWithinTraverse(int x, int y, bool traversePopups)
{
	return (VPANEL)0;
}

void CDragDropHelperPanel::PostChildPaint()
{
	int c = m_PaintList.Count();
	for ( int i = c - 1; i >= 0 ; --i )
	{
		DragHelperPanel_t& data = m_PaintList[ i ];

		Panel *panel = data.m_hPanel.Get();
		if ( !panel )
		{
			m_PaintList.Remove( i );
			continue;
		}

		Panel *dropPanel = panel->GetDragDropInfo()->m_hCurrentDrop.Get();
		if ( panel )
		{
			if ( !dropPanel )
			{
				panel->OnDraggablePanelPaint();
			}
			else
			{
				CUtlVector< Panel * > temp;
				CUtlVector< PHandle >& dragData = panel->GetDragDropInfo()->m_DragPanels;
				CUtlVector< KeyValues * >& msglist = panel->GetDragDropInfo()->m_DragData;
				int j, nDragData;
				nDragData = dragData.Count();
				for ( j = 0; j < nDragData; ++j )
				{
					Panel *pPanel = dragData[ j ].Get();
					if ( pPanel )
					{
						temp.AddToTail( pPanel );
					}
				}

				dropPanel->OnDroppablePanelPaint( msglist, temp );
			}
		}
	}

	if ( c == 0 )
	{
		MarkForDeletion();
	}
}

void CDragDropHelperPanel::AddPanel( Panel *current )
{
	if ( !current )
		return;

	Menu *hover = current->GetDragDropInfo()->m_hDropContextMenu.Get();

	surface()->MovePopupToFront( GetVPanel() );
	if ( hover && hover->IsPopup() )
	{
		surface()->MovePopupToFront( hover->GetVPanel() );
	}

	int c = m_PaintList.Count();
	for ( int i = 0; i < c; ++i )
	{
		if ( m_PaintList[ i ].m_hPanel.Get() == current )
			return;
	}

	DragHelperPanel_t data;
	data.m_hPanel				= current;
	m_PaintList.AddToTail( data );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *search - 
//-----------------------------------------------------------------------------
void CDragDropHelperPanel::RemovePanel( Panel *search )
{
	int c = m_PaintList.Count();
	for ( int i = c - 1 ; i >= 0; --i )
	{
		if ( m_PaintList[ i ].m_hPanel.Get() == search )
		{
			m_PaintList.Remove( i );
			return;
		}
	}
}
#endif
//-----------------------------------------------------------------------------
// Purpose: Enumerates panels under mouse x,y
// Input  : panelList - 
//			x - 
//			y - 
//			check - 
//-----------------------------------------------------------------------------
void Panel::FindDropTargetPanel_R( CUtlVector< VPANEL >& panelList, int x, int y, VPANEL check )
{
#if defined( VGUI_USEDRAGDROP )
	if ( !ipanel()->IsFullyVisible( check ) )
		return;

	if ( ::ShouldHandleInputMessage( check ) && ipanel()->IsWithinTraverse( check, x, y, false ) )
	{
		panelList.AddToTail( check );
	}

	CUtlVector< VPANEL > &children = ipanel()->GetChildren( check );
	int childCount = children.Count();
	for ( int i = 0; i < childCount; i++ )
	{
		VPANEL child = children[ i ];
		FindDropTargetPanel_R( panelList, x, y, child );
	}
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
// Output : Panel
//-----------------------------------------------------------------------------
Panel *Panel::FindDropTargetPanel()
{
#if defined( VGUI_USEDRAGDROP )
	if ( !s_DragDropHelper.Get() )
		return NULL;

	CUtlVector< VPANEL > hits;

	int x, y;
	input()->GetCursorPos( x, y );

	VPANEL embedded = surface()->GetEmbeddedPanel();
	VPANEL helper = s_DragDropHelper.Get()->GetVPanel();

	if ( surface()->IsCursorVisible() && surface()->IsWithin(x, y) )
	{
		// faster version of code below
		// checks through each popup in order, top to bottom windows
		int c = surface()->GetPopupCount();
		for (int i = c - 1; i >= 0 && hits.Count() == 0; i--)
		{
			VPANEL popup = surface()->GetPopup(i);
			if ( popup == embedded )
				continue;

			// Don't return helper panel!!!
			if ( popup == helper )
				continue;

			if ( !ipanel()->IsFullyVisible( popup ) )
				continue;

			FindDropTargetPanel_R( hits, x, y, popup );
		}

		// Check embedded
		if ( !hits.Count() )
		{
			FindDropTargetPanel_R( hits, x, y, embedded );
		}
	}

	// Nothing under mouse...
	if ( !hits.Count() )
		return NULL;

	// Return topmost panel under mouse, if it's visible to this .dll
	Panel *panel = NULL;
	int nCount = hits.Count();
	while ( --nCount >= 0 )
	{
		panel = ipanel()->GetPanel( hits[ nCount ], GetModuleName() );
		if ( panel )
			return panel;
	}
#endif
	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose: Mouse is on draggable panel and has started moving, but is not over a droppable panel yet
// Input  :  - 
//-----------------------------------------------------------------------------
void Panel::OnDraggablePanelPaint()
{
#if defined( VGUI_USEDRAGDROP )
	int sw, sh;
	GetSize( sw, sh );

	int x, y;
	input()->GetCursorPos( x, y );
	int w, h;

	w = min( sw, 80 );
	h = min( sh, 80 );
	x -= ( w >> 1 );
	y -= ( h >> 1 );

	surface()->DrawSetColor( m_clrDragFrame );
	surface()->DrawOutlinedRect( x, y, x + w, y + h );

	if ( m_pDragDrop->m_DragPanels.Count() > 1 )
	{
		surface()->DrawSetTextColor( m_clrDragFrame );
		surface()->DrawSetTextFont( m_infoFont );
		surface()->DrawSetTextPos( x + 5, y + 2 );

		wchar_t sz[ 64 ];
		V_swprintf_safe( sz, L"[ %i ]", m_pDragDrop->m_DragPanels.Count() );

		surface()->DrawPrintText( sz, wcslen( sz ) );
	}
#endif
}

//-----------------------------------------------------------------------------
// Purpose: Mouse is now over a droppable panel
// Input  : *dragPanel - 
//-----------------------------------------------------------------------------
void Panel::OnDroppablePanelPaint( CUtlVector< KeyValues * >& msglist, CUtlVector< Panel * >& dragPanels )
{
#if defined( VGUI_USEDRAGDROP )
	if ( !dragPanels.Count() )
		return;

	// Convert this panel's bounds to screen space
	int w, h;
	GetSize( w, h );

	int x, y;
	x = y = 0;
	LocalToScreen( x, y );

	surface()->DrawSetColor( m_clrDropFrame );
	// Draw 2 pixel frame
	surface()->DrawOutlinedRect( x, y, x + w, y + h );
	surface()->DrawOutlinedRect( x+1, y+1, x + w-1, y + h-1 );
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
// Output : Color
//-----------------------------------------------------------------------------
Color Panel::GetDropFrameColor()
{
#if defined( VGUI_USEDRAGDROP )
	return m_clrDropFrame;
#endif
	return Color(0, 0, 0, 0);
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
// Output : Color
//-----------------------------------------------------------------------------
Color Panel::GetDragFrameColor()
{
#if defined( VGUI_USEDRAGDROP )
	return m_clrDragFrame;
#endif
	return Color(0, 0, 0, 0);
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *data - 
//-----------------------------------------------------------------------------
void Panel::OnPanelDropped( CUtlVector< KeyValues * >& data )
{
	// Empty.  Derived classes would implement handlers here
}

//-----------------------------------------------------------------------------
// called on droptarget when draggable panel enters droptarget
//-----------------------------------------------------------------------------
void Panel::OnPanelEnteredDroppablePanel( CUtlVector< KeyValues * >& msglist )
{
	// Empty.  Derived classes would implement handlers here
}

//-----------------------------------------------------------------------------
// called on droptarget when draggable panel exits droptarget
//-----------------------------------------------------------------------------
void Panel::OnPanelExitedDroppablePanel ( CUtlVector< KeyValues * >& msglist )
{
	// Empty.  Derived classes would implement handlers here
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
//-----------------------------------------------------------------------------
void Panel::DragDropStartDragging()
{
#if defined( VGUI_USEDRAGDROP )
	// We somehow missed a mouse release, cancel the previous drag
	if ( g_DragDropCapture.Get() )
	{
		if ( HasParent( g_DragDropCapture.Get()->GetVPanel() ) )
			return;

		bool started = g_DragDropCapture->GetDragDropInfo()->m_bDragStarted;
		g_DragDropCapture->OnFinishDragging( true, (MouseCode)-1 );
		if ( started )
		{
			return;
		}
	}

	// Find actual target panel
	Panel *panel = GetDragPanel();
	if ( !panel )
		return;

	DragDrop_t *data = panel->GetDragDropInfo();
	if ( !data )
		return;

	if ( !panel->IsDragEnabled() )
		return;

	if ( data->m_bDragging )
		return;

	panel->OnStartDragging();
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool Panel::IsBeingDragged()
{
#if defined( VGUI_USEDRAGDROP )
	if ( !g_DragDropCapture.Get() )
		return false;

	if ( g_DragDropCapture.Get() == this )
		return true;

	// If we encounter a blocker, stop chaining
	if ( m_pDragDrop->m_bPreventChaining )
		return false;

	// Chain up
	if ( GetParent() )
	{
		return GetParent()->IsBeingDragged();
	}
#endif
	// No luck
	return false;
}

struct srect_t
{
	int x0, y0;
	int x1, y1;

	bool IsDegenerate()
	{
		if ( x1 - x0 <= 0 )
			return true;
		if ( y1 - y0 <= 0 )
			return true;
		return false;
	}
};

// Draws a filled rect of specified bounds, but omits the bounds of the skip panel from those bounds
void Panel::FillRectSkippingPanel( const Color &clr, int x, int y, int w, int h, Panel *skipPanel )
{
	int sx = 0, sy = 0, sw, sh;
	skipPanel->GetSize( sw, sh );
	skipPanel->LocalToScreen( sx, sy );
	ScreenToLocal( sx, sy );

	surface()->DrawSetColor( clr );

	srect_t r1;
	r1.x0 = x;
	r1.y0 = y;
	r1.x1 = x + w;
	r1.y1 = y + h;

	srect_t r2;
	r2.x0 = sx;
	r2.y0 = sy;
	r2.x1 = sx + sw;
	r2.y1 = sy + sh;

	int topy = r1.y0;
	int bottomy = r1.y1;

	// We'll descend vertically and draw:
	// 1 a possible bar across the top
	// 2 a possible bar across the bottom
	// 3 possible left bar
	// 4 possible right bar

	// Room at top?
	if ( r2.y0 > r1.y0 )
	{
		topy = r2.y0;

		surface()->DrawFilledRect( r1.x0, r1.y0, r1.x1, topy );
	}

	// Room at bottom?
	if ( r2.y1 < r1.y1 )
	{
		bottomy = r2.y1;

		surface()->DrawFilledRect( r1.x0, bottomy, r1.x1, r1.y1 );
	}

	// Room on left side?
	if ( r2.x0 > r1.x0 )
	{
		int left = r2.x0;

		surface()->DrawFilledRect( r1.x0, topy, left, bottomy );
	}

	// Room on right side
	if ( r2.x1 < r1.x1 )
	{
		int right = r2.x1;

		surface()->DrawFilledRect( right, topy, r1.x1, bottomy );
	}
}


//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *child - 
//-----------------------------------------------------------------------------
void Panel::SetSkipChildDuringPainting( Panel *child )
{
	m_SkipChild = child;
}

HPanel Panel::ToHandle() const
{
	return ivgui()->PanelToHandle( _vpanel );
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
Panel* Panel::NavigateUp()
{
	Panel *target = GetNavUp();
	if ( target )
	{
		NavigateFrom();
		target->m_LastNavDirection = ND_UP;
		target->NavigateTo();
	}

	return target;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
Panel* Panel::NavigateDown()
{
	Panel *target = GetNavDown();
	if ( target )
	{
		NavigateFrom();
		target->m_LastNavDirection = ND_DOWN;
		target->NavigateTo();
	}

	return target;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
Panel* Panel::NavigateLeft()
{
	Panel *target = GetNavLeft();
	if ( target )
	{
		NavigateFrom();
		target->m_LastNavDirection = ND_LEFT;
		target->NavigateTo();
	}
	return target;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
Panel* Panel::NavigateRight()
{
	Panel *target = GetNavRight();
	if ( target )
	{
		NavigateFrom();
		target->m_LastNavDirection = ND_RIGHT;
		target->NavigateTo();
	}
	return target;
}

Panel* Panel::NavigateActivate()
{
	Panel *target = GetNavActivate();
	if ( target )
	{
		NavigateFrom();
		target->m_LastNavDirection = ND_NONE;
		target->NavigateTo();
	}
	return target;
}

Panel* Panel::NavigateBack()
{
	Panel *target = GetNavBack();
	if ( target )
	{
		NavigateFrom();
		target->m_LastNavDirection = ND_NONE;
		target->NavigateTo();
	}
	return target;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::NavigateTo()
{
	if ( IsX360() )
	{
		RequestFocus( 0 );
	}

	CallParentFunction( new KeyValues( "OnNavigateTo", "panelName", GetName() ) );

	Panel *target = GetNavToRelay();
	if ( target )
	{
		NavigateFrom();
		target->m_LastNavDirection = ND_NONE;
		NavigateToChild( target );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::NavigateFrom()
{
	for ( int i = 0; i < GetChildCount(); ++i )
	{
		Panel* currentNav = GetChild(i);
		if ( currentNav != 0 )
		{
			currentNav->NavigateFrom();
		}
	}

	CallParentFunction( new KeyValues( "OnNavigateFrom", "panelName", GetName() ) );

	if ( m_pTooltips )
	{
		m_pTooltips->HideTooltip();
	}

	m_LastNavDirection = ND_NONE;
}

void Panel::NavigateToChild( Panel *pNavigateTo )
{
	for( int i = 0; i != GetChildCount(); ++i )
	{
		vgui::Panel *pChild = GetChild(i);
		if( pChild )
			pChild->NavigateFrom();
	}
	pNavigateTo->NavigateTo();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
Panel* Panel::SetNavUp( Panel* navUp )
{
	Panel* lastNav = m_NavUp;
	m_NavUp = navUp;

	if( navUp )
		m_sNavUpName = navUp->GetName();
	else
		m_sNavUpName.Clear();

	return lastNav;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
Panel* Panel::SetNavDown( Panel* navDown )
{
	Panel* lastNav = m_NavDown;
	m_NavDown = navDown;

	if( navDown )
		m_sNavDownName = navDown->GetName();
	else
		m_sNavDownName.Clear();

	return lastNav;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
Panel* Panel::SetNavLeft( Panel* navLeft )
{
	Panel* lastNav = m_NavLeft;
	m_NavLeft = navLeft;

	if( navLeft )
		m_sNavLeftName = navLeft->GetName();
	else
		m_sNavLeftName.Clear();

	return lastNav;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
Panel* Panel::SetNavRight( Panel* navRight )
{
	Panel* lastNav = m_NavRight;
	m_NavRight = navRight;

	if( navRight )
		m_sNavRightName = navRight->GetName();
	else
		m_sNavRightName.Clear();

	return lastNav;
}

Panel* Panel::SetNavToRelay( Panel* navToRelay )
{
	Panel* lastNav = m_NavToRelay;
	m_NavToRelay = navToRelay;

	return lastNav;
}

Panel* Panel::SetNavActivate( Panel* navActivate )
{
	Panel* lastNav = m_NavActivate;
	m_NavActivate = navActivate;

	return lastNav;
}

Panel* Panel::SetNavBack( Panel* navBack )
{
	Panel* lastNav = m_NavBack;
	m_NavBack = navBack;

	return lastNav;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
Panel::NAV_DIRECTION Panel::GetLastNavDirection()
{
	return m_LastNavDirection;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::OnNavigateTo( const char* panelName )
{
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::OnNavigateFrom( const char* panelName )
{
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::SetNavUp( const char* controlName )
{
	if ( controlName && 0 < Q_strlen( controlName ) && GetParent() != 0 )
	{
		m_NavUp = NULL;
		m_sNavUpName = controlName;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::SetNavDown( const char* controlName )
{
	if ( controlName && 0 < Q_strlen( controlName ) && GetParent() != 0 )
	{
		m_NavDown = NULL;
		m_sNavDownName = controlName;
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::SetNavLeft( const char* controlName )
{
	if ( controlName && 0 < Q_strlen( controlName ) && GetParent() != 0 )
	{
		m_NavLeft = NULL;
		m_sNavLeftName = controlName;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void Panel::SetNavRight( const char* controlName )
{
	if ( controlName && 0 < Q_strlen( controlName ) && GetParent() != 0 )
	{
		m_NavRight = NULL;
		m_sNavRightName = controlName;
	}
}

void Panel::SetNavToRelay( const char* controlName )
{
	if ( controlName && 0 < Q_strlen( controlName ) && GetParent() != 0 )
	{
		m_NavToRelay = NULL;
		m_sNavToRelayName = controlName;
	}
}

void Panel::SetNavActivate( const char* controlName )
{
	if ( controlName && 0 < Q_strlen( controlName ) && GetParent() != 0 )
	{
		m_NavActivate = NULL;
		m_sNavActivateName = controlName;
	}
}

void Panel::SetNavBack( const char* controlName )
{
	if ( controlName && 0 < Q_strlen( controlName ) && GetParent() != 0 )
	{
		m_NavBack = NULL;
		m_sNavBackName = controlName;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
vgui::Panel* Panel::GetNavUp( Panel *first )
{
	if ( !m_NavUp && m_sNavUpName.Length() > 0 )
	{
		Panel *pParent = GetParent();
		const char *pName = m_sNavUpName.String();
		while ( pParent && pName[ 0 ] == '<' )
		{
			pParent = pParent->GetParent();
			pName++;
		}

		if ( !pParent )
		{
			return NULL;
		}

		Panel *foundPanel = pParent->FindChildByName( pName, true );
		if ( foundPanel != 0 )
		{
			m_NavUp = foundPanel;
		}
	}

	vgui::Panel* nextPanel = m_NavUp;
	if( m_NavUp && m_NavUp != first && !m_NavUp->IsVisible() )
	{
		Panel *firstPanel = first == NULL ? this : first;
		nextPanel = nextPanel->GetNavUp( firstPanel );
	}

	return nextPanel;
}

vgui::Panel* Panel::GetNavDown( Panel *first )
{
	if ( !m_NavDown && m_sNavDownName.Length() > 0 )
	{
		Panel *pParent = GetParent();
		const char *pName = m_sNavDownName.String();
		while ( pParent && pName[ 0 ] == '<' )
		{
			pParent = pParent->GetParent();
			pName++;
		}

		if ( !pParent )
		{
			return NULL;
		}

		Panel* foundPanel = pParent->FindChildByName( pName, true );
		if ( foundPanel != 0 )
		{
			m_NavDown = foundPanel->GetPanel();
		}
	}

	vgui::Panel* nextPanel = m_NavDown;
	if( m_NavDown && m_NavDown != first && !m_NavDown->IsVisible() )
	{
		Panel *firstPanel = first == NULL ? this : first;
		nextPanel = nextPanel->GetNavDown( firstPanel );
	}

	return nextPanel;
}

vgui::Panel* Panel::GetNavLeft( Panel *first )
{
	if ( !m_NavLeft && m_sNavLeftName.Length() > 0 )
	{
		Panel *pParent = GetParent();
		const char *pName = m_sNavLeftName.String();
		while ( pParent && pName[ 0 ] == '<' )
		{
			pParent = pParent->GetParent();
			pName++;
		}

		if ( !pParent )
		{
			return NULL;
		}

		Panel* foundPanel = pParent->FindChildByName( pName, true );
		if ( foundPanel != 0 )
		{
			m_NavLeft = foundPanel->GetPanel();
		}
	}

	vgui::Panel* nextPanel = m_NavLeft;
	if( m_NavLeft && m_NavLeft != first && !m_NavLeft->IsVisible() )
	{
		Panel *firstPanel = first == NULL ? this : first;
		nextPanel = nextPanel->GetNavLeft( firstPanel );
	}

	return nextPanel;
}

vgui::Panel* Panel::GetNavRight( Panel *first )
{
	if ( !m_NavRight && m_sNavRightName.Length() > 0 )
	{
		Panel *pParent = GetParent();
		const char *pName = m_sNavRightName.String();
		while ( pParent && pName[ 0 ] == '<' )
		{
			pParent = pParent->GetParent();
			pName++;
		}

		if ( !pParent )
		{
			return NULL;
		}

		Panel* foundPanel = pParent->FindChildByName( pName, true );
		if ( foundPanel != 0 )
		{
			m_NavRight = foundPanel->GetPanel();
		}
	}

	vgui::Panel* nextPanel = m_NavRight;
	if( m_NavRight && m_NavRight != first && !m_NavRight->IsVisible() )
	{
		Panel *firstPanel = first == NULL ? this : first;
		nextPanel = nextPanel->GetNavRight( firstPanel );
	}

	return nextPanel;
}

vgui::Panel* Panel::GetNavToRelay( Panel *first )
{
	if ( !m_NavToRelay && m_sNavToRelayName.Length() > 0 )
	{
		Panel *pParent = this;
		const char *pName = m_sNavToRelayName.String();
		while ( pParent && pName[ 0 ] == '<' )
		{
			pParent = pParent->GetParent();
			pName++;
		}

		if ( !pParent )
		{
			return NULL;
		}

		Panel* foundPanel = pParent->FindChildByName( pName, true );
		if ( foundPanel != 0 )
		{
			m_NavToRelay = foundPanel->GetPanel();
		}
	}

	vgui::Panel* nextPanel = m_NavToRelay;
	if ( m_NavToRelay && m_NavToRelay != first && !m_NavToRelay->IsVisible() )
	{
		Panel *firstPanel = first == NULL ? this : first;
		nextPanel = nextPanel->GetNavToRelay( firstPanel );
	}

	return nextPanel;
}

vgui::Panel* Panel::GetNavActivate( Panel *first )
{
	if ( !m_NavActivate && m_sNavActivateName.Length() > 0 )
	{
		Panel *pParent = GetParent();
		const char *pName = m_sNavActivateName.String();
		while ( pParent && pName[ 0 ] == '<' )
		{
			pParent = pParent->GetParent();
			pName++;
		}

		if ( !pParent )
		{
			return NULL;
		}

		Panel* foundPanel = pParent->FindChildByName( pName, true );
		if ( foundPanel != 0 )
		{
			m_NavActivate = foundPanel->GetPanel();
		}
	}

	vgui::Panel* nextPanel = m_NavActivate;
	if ( m_NavActivate && m_NavActivate != first && !m_NavActivate->IsVisible() )
	{
		Panel *firstPanel = first == NULL ? this : first;
		nextPanel = nextPanel->GetNavActivate( firstPanel );
	}

	return nextPanel;
}

vgui::Panel* Panel::GetNavBack( Panel *first )
{
	if ( !m_NavBack && m_sNavBackName.Length() > 0 )
	{
		Panel *pParent = GetParent();
		const char *pName = m_sNavBackName.String();
		while ( pParent && pName[ 0 ] == '<' )
		{
			pParent = pParent->GetParent();
			pName++;
		}

		if ( !pParent )
		{
			return NULL;
		}

		Panel *foundPanel = pParent->FindChildByName( pName );
		if ( foundPanel )
		{
			m_NavBack = foundPanel;
		}
	}

	vgui::Panel* nextPanel = m_NavBack;
	if ( m_NavBack && m_NavBack != first && !m_NavBack->IsVisible() )
	{
		Panel *firstPanel = first == NULL ? this : first;
		nextPanel = nextPanel->GetNavBack( firstPanel );
	}

	return nextPanel;
}

vgui::Panel* Panel::GetNavUpPanel()
{
	return m_NavUp;
}

vgui::Panel* Panel::GetNavDownPanel()
{
	return m_NavDown;
}

vgui::Panel* Panel::GetNavLeftPanel()
{
	return m_NavLeft;
}

vgui::Panel* Panel::GetNavRightPanel()
{
	return m_NavRight;
}

vgui::Panel* Panel::GetNavToRelayPanel()
{
	return m_NavToRelay;
}

vgui::Panel* Panel::GetNavActivatePanel()
{
	return m_NavActivate;
}

vgui::Panel* Panel::GetNavBackPanel()
{
	return m_NavBack;
}

void Panel::SetConsoleStylePanel( bool bConsoleStyle )
{
	m_bIsConsoleStylePanel = bConsoleStyle;
}

bool Panel::IsConsoleStylePanel() const
{
	return m_bIsConsoleStylePanel;
}

//-----------------------------------------------------------------------------
// Purpose: Utility class for handling message map allocation
//-----------------------------------------------------------------------------
class CPanelMessageMapDictionary
{
public:
	CPanelMessageMapDictionary() : m_PanelMessageMapPool( sizeof(PanelMessageMap), 32, CUtlMemoryPool::GROW_FAST, "CPanelMessageMapDictionary::m_PanelMessageMapPool" )
	{
		m_MessageMaps.RemoveAll();
	}

	PanelMessageMap	*FindOrAddPanelMessageMap( char const *className );
	PanelMessageMap	*FindPanelMessageMap( char const *className );
private:

	struct PanelMessageMapDictionaryEntry
	{
		PanelMessageMap *map;
	};

	char const *StripNamespace( char const *className );
	
	CUtlDict< PanelMessageMapDictionaryEntry, int > m_MessageMaps;
	CUtlMemoryPool m_PanelMessageMapPool;
};


char const *CPanelMessageMapDictionary::StripNamespace( char const *className )
{
	if ( !strnicmp( className, "vgui::", 6 ) )
	{
		return className + 6;
	}
	return className;
}

//-----------------------------------------------------------------------------
// Purpose: Find but don't add mapping
//-----------------------------------------------------------------------------
PanelMessageMap *CPanelMessageMapDictionary::FindPanelMessageMap( char const *className )
{
	int lookup = m_MessageMaps.Find( StripNamespace( className ) );
	if ( lookup != m_MessageMaps.InvalidIndex() )
	{
		return m_MessageMaps[ lookup ].map;
	}
	return NULL;
}

#include <tier0/memdbgoff.h>
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
PanelMessageMap *CPanelMessageMapDictionary::FindOrAddPanelMessageMap( char const *className )
{
	PanelMessageMap *map = FindPanelMessageMap( className );
	if ( map )
		return map;

	PanelMessageMapDictionaryEntry entry;
	// use the alloc in place method of new
	entry.map = new (m_PanelMessageMapPool.Alloc(sizeof(PanelMessageMap))) PanelMessageMap;
	Construct(entry.map);
	m_MessageMaps.Insert( StripNamespace( className ), entry );
	return entry.map;
}
#include <tier0/memdbgon.h>

#if defined( VGUI_USEKEYBINDINGMAPS )
//-----------------------------------------------------------------------------
// Purpose: Utility class for handling keybinding map allocation
//-----------------------------------------------------------------------------
class CPanelKeyBindingMapDictionary
{
public:
	CPanelKeyBindingMapDictionary() : m_PanelKeyBindingMapPool( sizeof(PanelKeyBindingMap), 32, CUtlMemoryPool::GROW_FAST, "CPanelKeyBindingMapDictionary::m_PanelKeyBindingMapPool" )
	{
		m_MessageMaps.RemoveAll();
	}

	PanelKeyBindingMap	*FindOrAddPanelKeyBindingMap( char const *className );
	PanelKeyBindingMap	*FindPanelKeyBindingMap( char const *className );
private:

	struct PanelKeyBindingMapDictionaryEntry
	{
		PanelKeyBindingMap *map;
	};

	char const *StripNamespace( char const *className );
	
	CUtlDict< PanelKeyBindingMapDictionaryEntry, int > m_MessageMaps;
	CUtlMemoryPool m_PanelKeyBindingMapPool;
};


char const *CPanelKeyBindingMapDictionary::StripNamespace( char const *className )
{
	if ( !strnicmp( className, "vgui::", 6 ) )
	{
		return className + 6;
	}
	return className;
}

//-----------------------------------------------------------------------------
// Purpose: Find but don't add mapping
//-----------------------------------------------------------------------------
PanelKeyBindingMap *CPanelKeyBindingMapDictionary::FindPanelKeyBindingMap( char const *className )
{
	int lookup = m_MessageMaps.Find( StripNamespace( className ) );
	if ( lookup != m_MessageMaps.InvalidIndex() )
	{
		return m_MessageMaps[ lookup ].map;
	}
	return NULL;
}

#include <tier0/memdbgoff.h>
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
PanelKeyBindingMap *CPanelKeyBindingMapDictionary::FindOrAddPanelKeyBindingMap( char const *className )
{
	PanelKeyBindingMap *map = FindPanelKeyBindingMap( className );
	if ( map )
		return map;

	PanelKeyBindingMapDictionaryEntry entry;
	// use the alloc in place method of new
	entry.map = new (m_PanelKeyBindingMapPool.Alloc(sizeof(PanelKeyBindingMap))) PanelKeyBindingMap;
	Construct(entry.map);
	m_MessageMaps.Insert( StripNamespace( className ), entry );
	return entry.map;
}

#include <tier0/memdbgon.h>

CPanelKeyBindingMapDictionary& GetPanelKeyBindingMapDictionary()
{
	static CPanelKeyBindingMapDictionary dictionary;
	return dictionary;
}

#endif // VGUI_USEKEYBINDINGMAPS

CPanelMessageMapDictionary& GetPanelMessageMapDictionary()
{
	static CPanelMessageMapDictionary dictionary;
	return dictionary;
}

namespace vgui
{

	//-----------------------------------------------------------------------------
	// Purpose: 
	//-----------------------------------------------------------------------------
	PanelMessageMap *FindOrAddPanelMessageMap( char const *className )
	{
		return GetPanelMessageMapDictionary().FindOrAddPanelMessageMap( className );
	}

	//-----------------------------------------------------------------------------
	// Purpose: Find but don't add mapping
	//-----------------------------------------------------------------------------
	PanelMessageMap *FindPanelMessageMap( char const *className )
	{
		return GetPanelMessageMapDictionary().FindPanelMessageMap( className );
	}

#if defined( VGUI_USEKEYBINDINGMAPS )
	CPanelKeyBindingMapDictionary& GetPanelKeyBindingMapDictionary()
	{
		static CPanelKeyBindingMapDictionary dictionary;
		return dictionary;
	}
	//-----------------------------------------------------------------------------
	// Purpose: 
	//-----------------------------------------------------------------------------
	PanelKeyBindingMap *FindOrAddPanelKeyBindingMap( char const *className )
	{
		return GetPanelKeyBindingMapDictionary().FindOrAddPanelKeyBindingMap( className );
	}

	//-----------------------------------------------------------------------------
	// Purpose: Find but don't add mapping
	//-----------------------------------------------------------------------------
	PanelKeyBindingMap *FindPanelKeyBindingMap( char const *className )
	{
		return GetPanelKeyBindingMapDictionary().FindPanelKeyBindingMap( className );
	}
#endif // VGUI_USEKEYBINDINGMAPS

SortedPanel_t::SortedPanel_t( Panel *panel )
{
	pPanel = panel; pButton = dynamic_cast< Button* >( panel );
}


void VguiPanelGetSortedChildPanelList( Panel *pParentPanel, void *pSortedPanels )
{
	CUtlSortVector< SortedPanel_t, CSortedPanelYLess > *pList = reinterpret_cast< CUtlSortVector< SortedPanel_t, CSortedPanelYLess >* >( pSortedPanels );

	for ( int i = 0; i < pParentPanel->GetChildCount(); i++ )
	{
		// perform auto-layout on the child panel
		Panel *pPanel = pParentPanel->GetChild( i );
		if ( !pPanel || !pPanel->IsVisible() )
			continue;

		pList->Insert( SortedPanel_t( static_cast< Panel* >( pPanel ) ) );
	}
}

void VguiPanelGetSortedChildButtonList( Panel *pParentPanel, void *pSortedPanels, char *pchFilter /*= NULL*/, int nFilterType /*= 0*/ )
{
	CUtlSortVector< SortedPanel_t, CSortedPanelYLess > *pList = reinterpret_cast< CUtlSortVector< SortedPanel_t, CSortedPanelYLess >* >( pSortedPanels );

	for ( int i = 0; i < pParentPanel->GetChildCount(); i++ )
	{
		// perform auto-layout on the child panel
		Button *pPanel = dynamic_cast< Button* >( pParentPanel->GetChild( i ) );
		if ( !pPanel || !pPanel->IsVisible() )
			continue;

		if ( pchFilter && pchFilter[ 0 ] != '\0' )
		{
			char szBuff[ 128 ];
			pPanel->GetText( szBuff, sizeof( szBuff ) );

			// Prefix
			if ( nFilterType == 0 )
			{
				if ( !StringHasPrefix( szBuff, pchFilter ) )
				{
					continue;
				}
			}
			// Substring
			else if ( nFilterType == 1 )
			{
				if ( V_strstr( szBuff, pchFilter ) == NULL )
				{
					continue;
				}
			}
		}

		pList->Insert( SortedPanel_t( pPanel ) );
	}
}

int VguiPanelNavigateSortedChildButtonList( void *pSortedPanels, int nDir )
{
	CUtlSortVector< SortedPanel_t, CSortedPanelYLess > *pList = reinterpret_cast< CUtlSortVector< SortedPanel_t, CSortedPanelYLess >* >( pSortedPanels );

	if ( pList->Count() <= 0 )
		return -1;

	if ( nDir != 0 )
	{
		int nArmed = -1;
		for ( int i = 0; i < pList->Count(); i++ )
		{
			if ( (*pList)[ i ].pButton->IsArmed() )
			{
				nArmed = i;
				break;
			}
		}

		if ( nArmed == -1 )
		{
			(*pList)[ 0 ].pButton->SetArmed( true );
			return 0;
		}
		else
		{
			int nNewArmed = clamp( nArmed + nDir, 0, pList->Count() - 1 );
			if ( nNewArmed != nArmed )
			{
				(*pList)[ nArmed ].pButton->SetArmed( false );
			}

			(*pList)[ nNewArmed ].pButton->RequestFocus();
			(*pList)[ nNewArmed ].pButton->SetArmed( true );

			return nNewArmed;
		}
	}

	return -1;
}


int ComputeWide(Panel* pPanel, unsigned int& nBuildFlags, KeyValues *inResourceData, int nParentWide, int nParentTall, bool bComputingOther)
{
	int wide = pPanel->GetWide();

	const char *wstr = inResourceData->GetString("wide", NULL);
	if (wstr)
	{
		if (wstr[0] == 'f' || wstr[0] == 'F')
		{
			nBuildFlags |= Panel::BUILDMODE_SAVE_WIDE_FULL;
			wstr++;
		}
		else
		{
			if (wstr[0] == 'o' || wstr[0] == 'O')
			{
				wstr++;
				if (bComputingOther)
				{
					Warning("Wide and Tall of panel %s are set to be each other!\n", pPanel->GetName());
					return 0;
				}

				nBuildFlags |= Panel::BUILDMODE_SAVE_WIDE_PROPORTIONAL_TALL;
				wide = ComputeTall(pPanel, nBuildFlags, inResourceData, nParentWide, nParentTall, true);

				if (pPanel->IsProportional())
				{
					wide = scheme()->GetProportionalNormalizedValue(wide);
				}
			}
			else if (wstr[0] == 'p' || wstr[0] == 'P')
			{
				nBuildFlags |= Panel::BUILDMODE_SAVE_WIDE_PROPORTIONAL;
				wstr++;
			}
			else if (wstr[0] == 's' || wstr[0] == 'S')
			{
				nBuildFlags |= Panel::BUILDMODE_SAVE_WIDE_PROPORTIONAL_SELF;
				wstr++;
			}
		}

		float flWide = atof(wstr);
		if (!(nBuildFlags & Panel::BUILDMODE_SAVE_WIDE_PROPORTIONAL_TALL))
		{
			wide = atoi(wstr);
		}

		if (nBuildFlags & Panel::BUILDMODE_SAVE_WIDE_PROPORTIONAL_TALL)
		{
			wide = scheme()->GetProportionalScaledValueEx(pPanel->GetScheme(), wide);
			wide *= flWide;
		}
		else if (nBuildFlags & Panel::BUILDMODE_SAVE_WIDE_PROPORTIONAL)
		{
			wide = scheme()->GetProportionalScaledValueEx(pPanel->GetScheme(), wide);
			wide = nParentWide - wide;
			wide *= flWide;
		}
		else if (nBuildFlags & Panel::BUILDMODE_SAVE_WIDE_PROPORTIONAL_SELF)
		{
			wide = pPanel->GetWide() * flWide;
		}
		else
		{
			if (pPanel->IsProportional())
			{
				// scale the width up to our screen co-ords
				wide = scheme()->GetProportionalScaledValueEx(pPanel->GetScheme(), wide);
			}
			// now correct the alignment
			if (nBuildFlags & Panel::BUILDMODE_SAVE_WIDE_FULL)
			{
				wide = nParentWide - wide;
			}
		}
	}

	return wide;
}

int ComputeTall(Panel* pPanel, unsigned int& nBuildFlags, KeyValues *inResourceData, int nParentWide, int nParentTall, bool bComputingOther)
{
	int tall = pPanel->GetTall();

	// allow tall to be use the "fill" option, set to the height of the parent/screen
	const char *tstr = inResourceData->GetString("tall", NULL);
	if (tstr)
	{
		if (tstr[0] == 'f' || tstr[0] == 'F')
		{
			nBuildFlags |= Panel::BUILDMODE_SAVE_TALL_FULL;
			tstr++;
		}
		else
		{
			if (tstr[0] == 'o' || tstr[0] == 'O')
			{
				tstr++;
				if (bComputingOther)
				{
					Warning("Wide and Tall of panel %s are set to be each other!\n", pPanel->GetName());
					return 0;
				}

				nBuildFlags |= Panel::BUILDMODE_SAVE_TALL_PROPORTIONAL_WIDE;
				tall = ComputeWide(pPanel, nBuildFlags, inResourceData, nParentWide, nParentTall, true);
				if (pPanel->IsProportional())
				{
					tall = scheme()->GetProportionalNormalizedValue(tall);
				}
			}
			else if (tstr[0] == 'p' || tstr[0] == 'P')
			{
				nBuildFlags |= Panel::BUILDMODE_SAVE_TALL_PROPORTIONAL;
				tstr++;
			}
			else if (tstr[0] == 's' || tstr[0] == 'S')
			{
				nBuildFlags |= Panel::BUILDMODE_SAVE_TALL_PROPORTIONAL_SELF;
				tstr++;
			}
		}

		float flTall = atof(tstr);
		if (!(nBuildFlags & Panel::BUILDMODE_SAVE_TALL_PROPORTIONAL_WIDE))
		{
			tall = atoi(tstr);
		}

		if (nBuildFlags & Panel::BUILDMODE_SAVE_TALL_PROPORTIONAL_WIDE)
		{
			tall = scheme()->GetProportionalScaledValueEx(pPanel->GetScheme(), tall);
			tall *= flTall;
		}
		else if (nBuildFlags & Panel::BUILDMODE_SAVE_TALL_PROPORTIONAL)
		{
			// scale the height up to our screen co-ords
			tall = scheme()->GetProportionalScaledValueEx(pPanel->GetScheme(), tall);
			tall = nParentTall - tall;
			tall *= flTall;
		}
		else if(nBuildFlags & Panel::BUILDMODE_SAVE_TALL_PROPORTIONAL_SELF)
		{
			tall = pPanel->GetTall() * flTall;
		}
		else
		{
			if (pPanel->IsProportional())
			{
				// scale the height up to our screen co-ords
				tall = scheme()->GetProportionalScaledValueEx(pPanel->GetScheme(), tall);
			}
			// now correct the alignment
			if (nBuildFlags & Panel::BUILDMODE_SAVE_TALL_FULL)
			{
				tall = nParentTall - tall;
			}
		}
	}

	return tall;
}

int ComputePos( Panel* pPanel, const char *pszInput, int &nPos, const int& nSize, const int& nParentSize, const bool& bX, EOperator eOp)
{
	const int nFlagRightAlign = bX ? Panel::BUILDMODE_SAVE_XPOS_RIGHTALIGNED : Panel::BUILDMODE_SAVE_YPOS_BOTTOMALIGNED;
	const int nFlagCenterAlign = bX ? Panel::BUILDMODE_SAVE_XPOS_CENTERALIGNED : Panel::BUILDMODE_SAVE_YPOS_CENTERALIGNED;
	const int nFlagProportionalSelf = bX ? Panel::BUILDMODE_SAVE_XPOS_PROPORTIONAL_SELF : Panel::BUILDMODE_SAVE_YPOS_PROPORTIONAL_SELF;
	const int nFlagProportionalParent = bX ? Panel::BUILDMODE_SAVE_XPOS_PROPORTIONAL_PARENT : Panel::BUILDMODE_SAVE_YPOS_PROPORTIONAL_PARENT;

	int nFlags = 0;
	int nPosDelta = 0;
	if (pszInput)
	{
		// look for alignment flags
		if (pszInput[0] == 'r' || pszInput[0] == 'R')
		{
			nFlags |= nFlagRightAlign;
			pszInput++;
		}
		else if (pszInput[0] == 'c' || pszInput[0] == 'C')
		{
			nFlags |= nFlagCenterAlign;
			pszInput++;
		}

		if (pszInput[0] == 's' || pszInput[0] == 'S')
		{
			nFlags |= nFlagProportionalSelf;
			pszInput++;
		}
		else if (pszInput[0] == 'p' || pszInput[0] == 'P')
		{
			nFlags |= nFlagProportionalParent;
			pszInput++;
		}

		// get the value
		int nNewPos = atoi(pszInput);
		float flPos = atof(pszInput);

		float flProportion = 1.f;
		// scale the x up to our screen co-ords
		if ( pPanel->IsProportional() )
		{
			int nOldPos = nNewPos;
			nNewPos = scheme()->GetProportionalScaledValueEx( pPanel->GetScheme(), nNewPos );
			flProportion = (float)nNewPos / (float)nOldPos;
		}

		if (nFlags & nFlagProportionalSelf)
		{
			nPosDelta = nSize * flPos;
		}
		else if (nFlags & nFlagProportionalParent)
		{
			nPosDelta = nParentSize * flPos;
		}
		else
		{
			nPosDelta = nNewPos;
		}

		// now correct the alignment
		if (nFlags & nFlagRightAlign)
		{
			nNewPos = nParentSize - nPosDelta;
		}
		else if (nFlags & nFlagCenterAlign)
		{
			nNewPos = (nParentSize / 2) + nPosDelta;
		}
		else
		{
			nNewPos = nPosDelta;
		}

		switch (eOp)
		{
		case OP_ADD:
			nPos += nNewPos;
			break;
		case OP_SUB:
			nPos -= nNewPos;
			break;
		case OP_SET:
			nPos = nNewPos;
			break;
		}

		// Jump the sign if it's there
		if (pszInput[0] == '-' || pszInput[0] == '+')
			pszInput++;

		// Go past the number
		while (V_isdigit(pszInput[0]) || pszInput[0] == '.')
			pszInput++;

		// Peep if there's an operator
		if (pszInput && pszInput[0])
		{
			// Recurse!
			switch (pszInput[0])
			{
			case '+':
				ComputePos( pPanel, ++pszInput, nPos, nSize, nParentSize, bX, OP_ADD);
				break;
			case '-':
				ComputePos( pPanel, ++pszInput, nPos, nSize, nParentSize, bX, OP_SUB);
				break;
			}
		}

	}

	if (tf_debug_tabcontainer.GetBool() && !Q_stricmp("TabContainer", pPanel->GetName()))
	{
		Msg("TabContainer nFlags:%x nPos:%d nParentSize:%d nPosDelta:%d nSize:%d GetParent:%p (%s) pszInput:'%s'\n",
			nFlags, nPos, nParentSize, nPosDelta, nSize, pPanel->GetParent(), pPanel->GetParent() ? pPanel->GetParent()->GetName() : "??",
			pszInput ? pszInput : "??");
	}

	return nFlags;
}

}
