You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
8.0 KiB
355 lines
8.0 KiB
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
//=============================================================================
|
|
|
|
#include "vgui_controls/KeyBindingHelpDialog.h"
|
|
#include "vgui_controls/ListPanel.h"
|
|
#include "vgui/ISurface.h"
|
|
#include "vgui/IVGui.h"
|
|
#include "vgui/ILocalize.h"
|
|
#include "vgui/IInput.h"
|
|
#include "vgui/ISystem.h"
|
|
#include "KeyValues.h"
|
|
#include "vgui/Cursor.h"
|
|
#include "tier1/utldict.h"
|
|
#include "vgui_controls/KeyBoardEditorDialog.h"
|
|
|
|
// NOTE: This has to be the last file included!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
|
|
using namespace vgui;
|
|
|
|
// If the user holds the key bound to help down for this long, then the dialog will stay on automatically
|
|
#define KB_HELP_CONTINUE_SHOWING_TIME 1.0
|
|
|
|
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;
|
|
}
|
|
|
|
CKeyBindingHelpDialog::CKeyBindingHelpDialog( Panel *parent, Panel *panelToView, KeyBindingContextHandle_t handle, KeyCode code, int modifiers )
|
|
: BaseClass( parent, "KeyBindingHelpDialog" ),
|
|
m_Handle( handle ),
|
|
m_KeyCode( code ),
|
|
m_Modifiers( modifiers ),
|
|
m_bPermanent( false )
|
|
{
|
|
Assert( panelToView );
|
|
m_hPanel = panelToView;
|
|
|
|
m_pList = new ListPanel( 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/KeyBindingHelpDialog.res" );
|
|
|
|
if ( panelToView && panelToView->GetName() && panelToView->GetName()[0] )
|
|
{
|
|
SetTitle( panelToView->GetName(), true );
|
|
}
|
|
else
|
|
{
|
|
SetTitle( "#KBHelpDialogTitle", true );
|
|
}
|
|
|
|
SetSmallCaption( true );
|
|
SetMinimumSize( 400, 400 );
|
|
SetMinimizeButtonVisible( false );
|
|
SetMaximizeButtonVisible( false );
|
|
SetSizeable( true );
|
|
SetMoveable( true );
|
|
SetMenuButtonVisible( false );
|
|
|
|
SetVisible( true );
|
|
|
|
MoveToCenterOfScreen();
|
|
|
|
PopulateList();
|
|
|
|
m_flShowTime = system()->GetCurrentTime();
|
|
ivgui()->AddTickSignal( GetVPanel(), 0 );
|
|
|
|
input()->SetAppModalSurface( GetVPanel() );
|
|
}
|
|
|
|
CKeyBindingHelpDialog::~CKeyBindingHelpDialog()
|
|
{
|
|
if ( input()->GetAppModalSurface() == GetVPanel() )
|
|
{
|
|
input()->SetAppModalSurface( 0 );
|
|
}
|
|
}
|
|
|
|
void CKeyBindingHelpDialog::OnTick()
|
|
{
|
|
BaseClass::OnTick();
|
|
|
|
bool keyStillDown = IsHelpKeyStillBeingHeld();
|
|
|
|
double curtime = system()->GetCurrentTime();
|
|
double elapsed = curtime - m_flShowTime;
|
|
// After a second of holding the key, releasing the key will close the dialog
|
|
if ( elapsed > KB_HELP_CONTINUE_SHOWING_TIME )
|
|
{
|
|
if ( !keyStillDown )
|
|
{
|
|
MarkForDeletion();
|
|
return;
|
|
}
|
|
}
|
|
// Otherwise, if they tapped the key within a second and now have released...
|
|
else if ( !keyStillDown )
|
|
{
|
|
// Continue showing dialog indefinitely
|
|
ivgui()->RemoveTickSignal( GetVPanel() );
|
|
m_bPermanent = true;
|
|
}
|
|
}
|
|
|
|
// The key originally bound to help was pressed
|
|
void CKeyBindingHelpDialog::HelpKeyPressed()
|
|
{
|
|
// Don't kill while editor is being shown...
|
|
if ( m_hKeyBindingsEditor.Get() )
|
|
return;
|
|
|
|
if ( m_bPermanent )
|
|
{
|
|
MarkForDeletion();
|
|
}
|
|
}
|
|
|
|
bool CKeyBindingHelpDialog::IsHelpKeyStillBeingHeld()
|
|
{
|
|
bool keyDown = input()->IsKeyDown( m_KeyCode );
|
|
if ( !keyDown )
|
|
return false;
|
|
|
|
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;
|
|
}
|
|
|
|
if ( modifiers != m_Modifiers )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CKeyBindingHelpDialog::OnCommand( char const *cmd )
|
|
{
|
|
if ( !Q_stricmp( cmd, "OK" ) ||
|
|
!Q_stricmp( cmd, "cancel" ) ||
|
|
!Q_stricmp( cmd, "Close" ) )
|
|
{
|
|
MarkForDeletion();
|
|
}
|
|
else if ( !Q_stricmp( cmd, "edit" ) )
|
|
{
|
|
// Show the keybindings edit dialog
|
|
if ( m_hKeyBindingsEditor.Get() )
|
|
{
|
|
delete m_hKeyBindingsEditor.Get();
|
|
}
|
|
|
|
// Don't delete panel if H key is released...
|
|
|
|
m_hKeyBindingsEditor = new CKeyBoardEditorDialog( this, m_hPanel, m_Handle );
|
|
m_hKeyBindingsEditor->DoModal();
|
|
|
|
ivgui()->RemoveTickSignal( GetVPanel() );
|
|
m_bPermanent = true;
|
|
}
|
|
else
|
|
{
|
|
BaseClass::OnCommand( cmd );
|
|
}
|
|
}
|
|
|
|
void CKeyBindingHelpDialog::OnKeyCodeTyped(vgui::KeyCode code)
|
|
{
|
|
BaseClass::OnKeyCodeTyped( code );
|
|
}
|
|
|
|
void CKeyBindingHelpDialog::GetMappingList( Panel *panel, CUtlVector< PanelKeyBindingMap * >& maps )
|
|
{
|
|
PanelKeyBindingMap *map = panel->GetKBMap();
|
|
while ( map )
|
|
{
|
|
maps.AddToTail( map );
|
|
map = map->baseMap;
|
|
}
|
|
}
|
|
|
|
|
|
void CKeyBindingHelpDialog::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 );
|
|
}
|
|
}
|
|
|
|
struct ListInfo_t
|
|
{
|
|
PanelKeyBindingMap *m_pMap;
|
|
Panel *m_pPanel;
|
|
};
|
|
|
|
void CKeyBindingHelpDialog::PopulateList()
|
|
{
|
|
m_pList->DeleteAllItems();
|
|
|
|
int i, j;
|
|
|
|
CUtlVector< ListInfo_t > maps;
|
|
vgui::Panel *pPanel = m_hPanel;
|
|
while ( pPanel->IsKeyBindingChainToParentAllowed() )
|
|
{
|
|
PanelKeyBindingMap *map = pPanel->GetKBMap();
|
|
while ( map )
|
|
{
|
|
int k;
|
|
int c = maps.Count();
|
|
for ( k = 0; k < c; ++k )
|
|
{
|
|
if ( maps[k].m_pMap == map )
|
|
break;
|
|
}
|
|
if ( k == c )
|
|
{
|
|
int iMap = maps.AddToTail( );
|
|
maps[iMap].m_pMap = map;
|
|
maps[iMap].m_pPanel = pPanel;
|
|
}
|
|
map = map->baseMap;
|
|
}
|
|
|
|
pPanel = pPanel->GetParent();
|
|
if ( !pPanel )
|
|
break;
|
|
}
|
|
|
|
CUtlRBTree< KeyValues *, int > sorted( 0, 0, BindingLessFunc );
|
|
|
|
// add header item
|
|
int c = maps.Count();
|
|
for ( i = 0; i < c; ++i )
|
|
{
|
|
PanelKeyBindingMap *m = maps[ i ].m_pMap;
|
|
pPanel = maps[i].m_pPanel;
|
|
Assert( m );
|
|
|
|
int bindings = m->boundkeys.Count();
|
|
for ( j = 0; j < bindings; ++j )
|
|
{
|
|
BoundKey_t *kbMap = &m->boundkeys[ 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 = 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;
|
|
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();
|
|
}
|