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

#include "vgui_controls/KeyBoardEditorDialog.h"
#include "vgui_controls/ListPanel.h"
#include "vgui_controls/Button.h"
#include "vgui_controls/TextEntry.h"
#include "vgui/ISurface.h"
#include "vgui/IInput.h"
#include "vgui/IVGui.h"
#include "vgui/ILocalize.h"
#include "KeyValues.h"
#include "vgui/Cursor.h"
#include "tier1/utldict.h"

// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"


using namespace vgui;

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;
}

CKeyBoardEditorPage::SaveMapping_t::SaveMapping_t() : map( 0 )
{
}

CKeyBoardEditorPage::SaveMapping_t::SaveMapping_t( const SaveMapping_t& src )
{
	map = src.map;
	current = src.current;
	original = src.original;
}

//-----------------------------------------------------------------------------
// Purpose: Special list subclass to handle drawing of trap mode prompt on top of
//			lists client area
//-----------------------------------------------------------------------------
class VControlsListPanel : public ListPanel
{
	DECLARE_CLASS_SIMPLE( VControlsListPanel, ListPanel );

public:
	// Construction
					VControlsListPanel( vgui::Panel *parent, const char *listName );
	virtual			~VControlsListPanel();

	// Start/end capturing
	virtual void	StartCaptureMode(vgui::HCursor hCursor = NULL);
	virtual void	EndCaptureMode(vgui::HCursor hCursor = NULL);
	virtual bool	IsCapturing();

	// Set which item should be associated with the prompt
	virtual void	SetItemOfInterest(int itemID);
	virtual int		GetItemOfInterest();

	virtual void	OnMousePressed(vgui::MouseCode code);
	virtual void	OnMouseDoublePressed(vgui::MouseCode code);
	
	KEYBINDING_FUNC( clearbinding, KEY_DELETE, 0, OnClearBinding, 0, 0 );

private:
	void ApplySchemeSettings(vgui::IScheme *pScheme );

	// Are we showing the prompt?
	bool			m_bCaptureMode;
	// If so, where?
	int				m_nClickRow;
	// Font to use for showing the prompt
	vgui::HFont		m_hFont;
	// panel used to edit
	class CInlineEditPanel *m_pInlineEditPanel;
	int m_iMouseX, m_iMouseY;
};

//-----------------------------------------------------------------------------
// Purpose: panel used for inline editing of key bindings
//-----------------------------------------------------------------------------
class CInlineEditPanel : public vgui::Panel
{
	DECLARE_CLASS_SIMPLE( CInlineEditPanel, vgui::Panel );

public:
	CInlineEditPanel() : vgui::Panel(NULL, "InlineEditPanel")
	{
	}

	virtual void Paint()
	{
		int wide, tall;
		GetSize(wide, tall);

		// Draw a white rectangle around that cell
		vgui::surface()->DrawSetColor( 63, 63, 63, 255 );
		vgui::surface()->DrawFilledRect( 0, 0, wide, tall );

		vgui::surface()->DrawSetColor( 0, 255, 0, 255 );
		vgui::surface()->DrawOutlinedRect( 0, 0, wide, tall );
	}

	virtual void OnKeyCodeTyped(KeyCode code)
	{
		// forward up
		if (GetParent())
		{
			GetParent()->OnKeyCodeTyped(code);
		}
	}

	virtual void ApplySchemeSettings(IScheme *pScheme)
	{
		Panel::ApplySchemeSettings(pScheme);
		SetBorder(pScheme->GetBorder("DepressedButtonBorder"));
	}

	void OnMousePressed(vgui::MouseCode code)
	{
		// forward up mouse pressed messages to be handled by the key options
		if (GetParent())
		{
			GetParent()->OnMousePressed(code);
		}
	}
};

//-----------------------------------------------------------------------------
// Purpose: Construction
//-----------------------------------------------------------------------------
VControlsListPanel::VControlsListPanel( vgui::Panel *parent, const char *listName )	: BaseClass( parent, listName )
{
	m_bCaptureMode	= false;
	m_nClickRow		= 0;
	m_pInlineEditPanel = new CInlineEditPanel();
	m_hFont = INVALID_FONT;
}

//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
VControlsListPanel::~VControlsListPanel()
{
	m_pInlineEditPanel->MarkForDeletion();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void VControlsListPanel::ApplySchemeSettings(IScheme *pScheme )
{
	BaseClass::ApplySchemeSettings( pScheme );
	m_hFont	= pScheme->GetFont("DefaultVerySmall", IsProportional() ); 
}

//-----------------------------------------------------------------------------
// Purpose: Start capture prompt display
//-----------------------------------------------------------------------------
void VControlsListPanel::StartCaptureMode( HCursor hCursor )
{
	m_bCaptureMode = true;
	EnterEditMode(m_nClickRow, 1, m_pInlineEditPanel);
	input()->SetMouseFocus(m_pInlineEditPanel->GetVPanel());
	input()->SetMouseCapture(m_pInlineEditPanel->GetVPanel());

	if (hCursor)
	{
		m_pInlineEditPanel->SetCursor(hCursor);

		// save off the cursor position so we can restore it
		vgui::input()->GetCursorPos( m_iMouseX, m_iMouseY );
	}
}

void VControlsListPanel::OnClearBinding()
{
	if ( m_bCaptureMode )
		return;

	if ( GetItemOfInterest() < 0 )
		return;

	PostMessage( GetParent()->GetVPanel(), new KeyValues( "ClearBinding", "item", GetItemOfInterest() ) );
}

//-----------------------------------------------------------------------------
// Purpose: Finish capture prompt display
//-----------------------------------------------------------------------------
void VControlsListPanel::EndCaptureMode( HCursor hCursor )
{
	m_bCaptureMode = false;
	input()->SetMouseCapture(NULL);
	LeaveEditMode();
	RequestFocus();
	input()->SetMouseFocus(GetVPanel());
	if (hCursor)
	{
		m_pInlineEditPanel->SetCursor(hCursor);
		surface()->SetCursor(hCursor);	
		if ( hCursor != dc_none )
		{
			vgui::input()->SetCursorPos ( m_iMouseX, m_iMouseY );	
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Set active row column
//-----------------------------------------------------------------------------
void VControlsListPanel::SetItemOfInterest(int itemID)
{
	m_nClickRow	= itemID;
}

//-----------------------------------------------------------------------------
// Purpose: Retrieve row, column of interest
//-----------------------------------------------------------------------------
int VControlsListPanel::GetItemOfInterest()
{
	return m_nClickRow;
}

//-----------------------------------------------------------------------------
// Purpose: returns true if we're currently waiting to capture a key
//-----------------------------------------------------------------------------
bool VControlsListPanel::IsCapturing( void )
{
	return m_bCaptureMode;
}

//-----------------------------------------------------------------------------
// Purpose: Forwards mouse pressed message up to keyboard page when in capture
//-----------------------------------------------------------------------------
void VControlsListPanel::OnMousePressed(vgui::MouseCode code)
{
	if (IsCapturing())
	{
		// forward up mouse pressed messages to be handled by the key options
		if (GetParent())
		{
			GetParent()->OnMousePressed(code);
		}
	}
	else
	{
		BaseClass::OnMousePressed(code);
	}
}


//-----------------------------------------------------------------------------
// Purpose: input handler
//-----------------------------------------------------------------------------
void VControlsListPanel::OnMouseDoublePressed( vgui::MouseCode code )
{
	int c = GetSelectedItemsCount();
	if ( c > 0 )
	{
		// enter capture mode
		OnKeyCodeTyped(KEY_ENTER);
	}
	else
	{
		BaseClass::OnMouseDoublePressed(code);
	}
}

CKeyBoardEditorPage::CKeyBoardEditorPage( Panel *parent, Panel *panelToEdit, KeyBindingContextHandle_t handle )
	: BaseClass( parent, "KeyBoardEditorPage" ),
	m_pPanel( panelToEdit ),
	m_Handle( handle )
{
	Assert( m_pPanel );

	m_pList = new VControlsListPanel( this, "KeyBindings" );
	m_pList->SetIgnoreDoubleClick( true );
	m_pList->AddColumnHeader(0, "Action", "#KBEditorBindingName", 175, 0);
	m_pList->AddColumnHeader(1, "Binding", "#KBEditorBinding", 175, 0);
	m_pList->AddColumnHeader(2, "Description", "#KBEditorDescription", 300, 0);

	LoadControlSettings( "resource/KeyBoardEditorPage.res" );

	SaveMappings();
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
//-----------------------------------------------------------------------------
CKeyBoardEditorPage::~CKeyBoardEditorPage()
{
	int c = m_Save.Count();
	for ( int i = 0 ; i  < c; ++i )
	{
		delete m_Save[ i ];
	}
	m_Save.RemoveAll();
}

void CKeyBoardEditorPage::ApplySchemeSettings( IScheme *scheme )
{
	BaseClass::ApplySchemeSettings( scheme );
	PopulateList();
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
//-----------------------------------------------------------------------------
void CKeyBoardEditorPage::SaveMappings()
{
	Assert( m_Save.Count() == 0 );

	CUtlVector< PanelKeyBindingMap * > maps;
	GetMappingList( m_pPanel, maps );

	// add header item
	int c = maps.Count();
	for ( int i = 0; i < c; ++i )
	{
		PanelKeyBindingMap *m = maps[ i ];
		SaveMapping_t	*sm = new SaveMapping_t;
		sm->map			= m;
		sm->current = m->boundkeys;
		sm->original = m->boundkeys;
		m_Save.AddToTail( sm );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
//-----------------------------------------------------------------------------
void CKeyBoardEditorPage::UpdateCurrentMappings()
{
	int c = m_Save.Count();
	for ( int i = 0 ; i < c; ++i )
	{
		PanelKeyBindingMap *m = m_Save[ i ]->map;
		Assert( m );
		m_Save[ i ]->current = m->boundkeys;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
//-----------------------------------------------------------------------------
void CKeyBoardEditorPage::RestoreMappings()
{
	int c = m_Save.Count();
	for ( int i = 0; i < c; ++i )
	{
		SaveMapping_t *sm = m_Save[ i ];
		sm->current = sm->original;
	}
}

void CKeyBoardEditorPage::ApplyMappings()
{
	int c = m_Save.Count();
	for ( int i = 0; i < c; ++i )
	{
		SaveMapping_t *sm = m_Save[ i ];
		sm->map->boundkeys = sm->current;
	}
}


//-----------------------------------------------------------------------------
// Purpose: User clicked on item: remember where last active row/column was
//-----------------------------------------------------------------------------
void CKeyBoardEditorPage::ItemSelected()
{
	int c = m_pList->GetSelectedItemsCount();
	if ( c > 0 )
	{
		m_pList->SetItemOfInterest( m_pList->GetSelectedItem( 0 ) );
	}
}

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

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

	int r = m_pList->GetItemOfInterest();

	// Retrieve clicked row and column
	m_pList->EndCaptureMode(dc_arrow);

	// Find item for this row
	KeyValues *item = m_pList->GetItem(r);
	if ( item )
	{
		BoundKey_t *kbMap = reinterpret_cast< BoundKey_t * >( item->GetPtr( "Item", 0 ) );
		if ( kbMap )
		{
			KeyBindingMap_t *binding = m_pPanel->LookupBindingByKeyCode( code, modifiers );
			if ( binding && Q_stricmp( kbMap->bindingname, binding->bindingname ) )
			{
				// Key is already rebound!!!
				Warning( "Can't bind to '%S', key is already bound to '%s'\n",
					Panel::KeyCodeToDisplayString( code ), binding->bindingname );
				return;
			}

			kbMap->keycode		= code;
			kbMap->modifiers	= modifiers; 

			PopulateList();
		}

		KeyBindingMap_t *bindingMap = reinterpret_cast< KeyBindingMap_t * >( item->GetPtr( "Unbound", 0 ) );
		if ( bindingMap )
		{
			KeyBindingMap_t *binding = m_pPanel->LookupBindingByKeyCode( code, modifiers );
			if ( binding && Q_stricmp( bindingMap->bindingname, binding->bindingname ) )
			{
				// Key is already rebound!!!
				Warning( "Can't bind to '%S', key is already bound to '%s'\n",
					Panel::KeyCodeToDisplayString( code ), binding->bindingname );
				return;
			}

			// Need to add to current entries
			m_pPanel->AddKeyBinding( bindingMap->bindingname, code, modifiers );
			UpdateCurrentMappings();
			PopulateList();
		}
	}
}

void CKeyBoardEditorPage::OnPageHide()
{
	if ( m_pList->IsCapturing() )
	{
		// Cancel capturing
		m_pList->EndCaptureMode(dc_arrow);
	}
}

//-----------------------------------------------------------------------------
// Purpose: binds double-clicking or hitting enter in the keybind list to changing the key
//-----------------------------------------------------------------------------
void CKeyBoardEditorPage::OnKeyCodeTyped(vgui::KeyCode code)
{
	switch ( code )
	{
	case KEY_ENTER:
        {
			if ( !m_pList->IsCapturing() )
			{
                OnCommand( "ChangeKey" );
			}
			else
			{
				BindKey( code );
			}
		}
		break;
	case KEY_LSHIFT:
	case KEY_RSHIFT:
	case KEY_LALT:
	case KEY_RALT:
	case KEY_LCONTROL:
	case KEY_RCONTROL:
		{
			// Swallow these
			break;
		}
		break;
	default:
		{
			if ( m_pList->IsCapturing() )
			{
				BindKey( code );
			}
			else
			{
				BaseClass::OnKeyCodeTyped(code);
			}
		}
	}
}

void CKeyBoardEditorPage::OnCommand( char const *cmd )
{
	if ( !m_pList->IsCapturing() && !Q_stricmp( cmd, "ChangeKey" ) )
	{
		m_pList->StartCaptureMode(dc_blank);
	}
	else
	{
		BaseClass::OnCommand( cmd );
	}
}

void CKeyBoardEditorPage::OnSaveChanges()
{
	ApplyMappings();
}

void CKeyBoardEditorPage::OnRevert()
{
	RestoreMappings();
	PopulateList();
}

void CKeyBoardEditorPage::OnUseDefaults()
{
	m_pPanel->RevertKeyBindingsToDefault();
	UpdateCurrentMappings();
	PopulateList();
}

void CKeyBoardEditorPage::GetMappingList( Panel *panel, CUtlVector< PanelKeyBindingMap * >& maps )
{
	PanelKeyBindingMap *map = panel->GetKBMap();
	while ( map )
	{
		maps.AddToTail( map );
		map = map->baseMap;
	}
}

static bool BindingLessFunc( KeyValues * const & lhs, KeyValues * const &rhs )
{
	KeyValues *p1, *p2;

	p1 = const_cast< KeyValues * >( lhs );
	p2 = const_cast< KeyValues * >( rhs );
	return ( Q_stricmp( p1->GetString( "Action" ), p2->GetString( "Action" ) ) < 0 ) ? true : false;
}

void CKeyBoardEditorPage::AnsiText( char const *token, char *out, size_t buflen )
{
	out[ 0 ] = 0;

	wchar_t *str = g_pVGuiLocalize->Find( token );
	if ( !str )
	{
		Q_strncpy( out, token, buflen );
	}
	else
	{
		g_pVGuiLocalize->ConvertUnicodeToANSI( str, out, buflen );
	}
}

void CKeyBoardEditorPage::PopulateList()
{
	m_pList->DeleteAllItems();

	int i, j;

	CUtlRBTree< KeyValues *, int >	sorted( 0, 0, BindingLessFunc );

	// add header item
	int c = m_Save.Count();
	for ( i = 0; i < c; ++i )
	{
		SaveMapping_t* sm = m_Save[ i ];

		PanelKeyBindingMap *m = sm->map;
		Assert( m );

		int bindings = sm->current.Count();
		for ( j = 0; j < bindings; ++j )
		{
			BoundKey_t *kbMap = &sm->current[ j ];
			Assert( kbMap );

			// Create a new: blank item
			KeyValues *item = new KeyValues( "Item" );
			
			// Fill in data
			char loc[ 128 ];
			Q_snprintf( loc, sizeof( loc ), "#%s", kbMap->bindingname );

			char ansi[ 256 ];
			AnsiText( loc, ansi, sizeof( ansi ) );

			item->SetString( "Action", ansi );
			item->SetWString( "Binding", Panel::KeyCodeModifiersToDisplayString( (KeyCode)kbMap->keycode, kbMap->modifiers ) );

			// Find the binding
			KeyBindingMap_t *bindingMap = m_pPanel->LookupBinding( kbMap->bindingname );
			if ( bindingMap && 
				 bindingMap->helpstring )
			{
				AnsiText( bindingMap->helpstring, ansi, sizeof( ansi ) );
				item->SetString( "Description", ansi);
			}
			
			item->SetPtr( "Item", kbMap );			

			sorted.Insert( item );
		}

		// Now try and find any "unbound" keys...
		int mappings = m->entries.Count();
		for ( j = 0; j < mappings; ++j )
		{
			KeyBindingMap_t *kbMap = &m->entries[ j ];

			// See if it's bound
			CUtlVector< BoundKey_t * > list;
			m_pPanel->LookupBoundKeys( kbMap->bindingname, list );
			if ( list.Count() > 0 )
				continue;

			// Not bound, add a placeholder entry
			// Create a new: blank item
			KeyValues *item = new KeyValues( "Item" );
			
			// fill in data
			char loc[ 128 ];
			Q_snprintf( loc, sizeof( loc ), "#%s", kbMap->bindingname );
			
			char ansi[ 256 ];
			AnsiText( loc, ansi, sizeof( ansi ) );

			item->SetString( "Action", ansi );
			item->SetWString( "Binding", L"" );
			if ( kbMap->helpstring )
			{
				AnsiText( kbMap->helpstring, ansi, sizeof( ansi ) );
				item->SetString( "Description", ansi );
			}

			item->SetPtr( "Unbound", kbMap );						

			sorted.Insert( item );
		}
	}

	for ( j = sorted.FirstInorder() ; j != sorted.InvalidIndex(); j = sorted.NextInorder( j ) )
	{
		KeyValues *item = sorted[ j ];

		// Add to list
		m_pList->AddItem( item, 0, false, false );

		item->deleteThis();
	}

	sorted.RemoveAll();
}

void CKeyBoardEditorPage::OnClearBinding( int item )
{
	// Find item for this row
	KeyValues *kv = m_pList->GetItem(item );
	if ( !kv )
	{
		return;
	}

	BoundKey_t *kbMap = reinterpret_cast< BoundKey_t * >( kv->GetPtr( "Item", 0 ) );
	if ( !kbMap )
	{
		return;
	}

	kbMap->keycode		= KEY_NONE;
	kbMap->modifiers	= 0; 

	PopulateList();
}

CKeyBoardEditorSheet::CKeyBoardEditorSheet( Panel *parent, Panel *panelToEdit, KeyBindingContextHandle_t handle )
	: BaseClass( parent, "KeyBoardEditorSheet" ),
	m_bSaveToExternalFile( false ),
	m_Handle( handle ),
	m_SaveFileName( UTL_INVAL_SYMBOL ),
	m_SaveFilePathID( UTL_INVAL_SYMBOL )
{
	m_hPanel = panelToEdit;

	SetSmallTabs( true );

	// Create this sheet and add the subcontrols
	CKeyBoardEditorPage *active = NULL;

	int subCount = Panel::GetPanelsWithKeyBindingsCount( handle );
	for ( int i = 0; i < subCount; ++i )
	{
		Panel *p = Panel::GetPanelWithKeyBindings( handle, i );
		if ( !p )
			continue;

		// Don't display panels with no keymappings
		if ( p->GetKeyMappingCount() == 0 )
			continue;

        CKeyBoardEditorPage *newPage = new CKeyBoardEditorPage( this, p, handle );
		AddPage( newPage, p->GetName() );
		if ( p == panelToEdit )
		{
			active = newPage;
		}
	}

	if ( active )
	{
		SetActivePage( active );
	}

	LoadControlSettings( "resource/KeyBoardEditorSheet.res" );
}

void CKeyBoardEditorSheet::SetKeybindingsSaveFile( char const *filename, char const *pathID /*= 0*/ )
{
	Assert( filename );
	m_bSaveToExternalFile = true;
	m_SaveFileName = filename;
	if ( pathID != NULL )
	{
		m_SaveFilePathID = pathID;
	}
	else
	{
		m_SaveFilePathID = UTL_INVAL_SYMBOL;
	}
}

void CKeyBoardEditorSheet::OnSaveChanges()
{
	int c = GetNumPages();
	for ( int i = 0 ; i < c; ++i )
	{
		CKeyBoardEditorPage *page = static_cast< CKeyBoardEditorPage * >( GetPage( i ) );
		page->OnSaveChanges();
	}

	if ( m_bSaveToExternalFile )
	{
		m_hPanel->SaveKeyBindingsToFile( m_Handle, m_SaveFileName.String(), m_SaveFilePathID.IsValid() ? m_SaveFilePathID.String() : NULL );
	}
	else
	{
		m_hPanel->SaveKeyBindings( m_Handle );
	}
}

void CKeyBoardEditorSheet::OnRevert()
{
	int c = GetNumPages();
	for ( int i = 0 ; i < c; ++i )
	{
		CKeyBoardEditorPage *page = static_cast< CKeyBoardEditorPage * >( GetPage( i ) );
		page->OnRevert();
	}
}

void CKeyBoardEditorSheet::OnUseDefaults()
{
	int c = GetNumPages();
	for ( int i = 0 ; i < c; ++i )
	{
		CKeyBoardEditorPage *page = static_cast< CKeyBoardEditorPage * >( GetPage( i ) );
		page->OnUseDefaults();
	}
}

CKeyBoardEditorDialog::CKeyBoardEditorDialog( Panel *parent, Panel *panelToEdit, KeyBindingContextHandle_t handle )
	: BaseClass( parent, "KeyBoardEditorDialog" )
{
	m_pSave = new Button( this, "Save", "#KBEditorSave", this, "save" );
	m_pCancel = new Button( this, "Cancel", "#KBEditorCancel", this, "cancel" );
	m_pRevert = new Button( this, "Revert", "#KBEditorRevert", this, "revert" );
	m_pUseDefaults = new Button( this, "Defaults", "#KBEditorUseDefaults", this, "defaults" );

	m_pKBEditor = new CKeyBoardEditorSheet( this, panelToEdit, handle );

	LoadControlSettings( "resource/KeyBoardEditorDialog.res" );

	SetTitle( "#KBEditorTitle", true );

	SetSmallCaption( true );
	SetMinimumSize( 640, 200 );
	SetMinimizeButtonVisible( false );
	SetMaximizeButtonVisible( false );
	SetSizeable( true );
	SetMoveable( true );
	SetMenuButtonVisible( false );

	SetVisible( true );

	MoveToCenterOfScreen();
}

void CKeyBoardEditorDialog::OnCommand( char const *cmd )
{
	if ( !Q_stricmp( cmd, "save" ) )
	{
		m_pKBEditor->OnSaveChanges();
		MarkForDeletion();
	}
	else if ( !Q_stricmp( cmd, "cancel" ) ||
		      !Q_stricmp( cmd, "Close" ) )
	{
		m_pKBEditor->OnRevert();
		MarkForDeletion();
	}
	else if ( !Q_stricmp( cmd, "revert" ) )
	{
		m_pKBEditor->OnRevert();
	}
	else if ( !Q_stricmp( cmd, "defaults" ) )
	{
		m_pKBEditor->OnUseDefaults();
	}
	else
	{
		BaseClass::OnCommand( cmd );
	}
}

void CKeyBoardEditorDialog::SetKeybindingsSaveFile( char const *filename, char const *pathID /*= 0*/ )
{
	m_pKBEditor->SetKeybindingsSaveFile( filename, pathID );
}