2022-08-22 01:10:18 +02:00
/******************************************************************************
2021-12-25 22:36:38 +01:00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
File : IConsole . cpp
2023-09-17 11:38:00 +02:00
Date : 15 : 06 : 2021
2021-12-25 22:36:38 +01:00
Author : Kawe Mazidjatari
2022-01-12 02:53:07 +01:00
Purpose : Implements the in - game console front - end
2021-12-25 22:36:38 +01:00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
History :
- 15 : 06 : 2021 | 14 : 56 : Created by Kawe Mazidjatari
2022-09-09 19:47:31 +02:00
- 07 : 08 : 2021 | 15 : 22 : Multi - thread ' CommandExecute ' operations to prevent deadlock in render thread
- 07 : 08 : 2021 | 15 : 25 : Fix a race condition that occurred when detaching the ' CommandExecute ' thread
2021-12-25 22:36:38 +01:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-01-12 02:53:07 +01:00
# include "core/stdafx.h"
# include "core/init.h"
2022-04-26 20:24:51 +02:00
# include "core/resource.h"
2022-08-19 21:33:31 +02:00
# include "tier0/frametask.h"
2022-01-18 11:23:14 +01:00
# include "tier0/commandline.h"
2022-01-12 02:53:07 +01:00
# include "windows/id3dx.h"
# include "windows/console.h"
2022-04-26 20:24:51 +02:00
# include "windows/resource.h"
2023-05-10 00:05:38 +02:00
# include "engine/cmd.h"
2022-01-12 02:53:07 +01:00
# include "gameui/IConsole.h"
2024-02-24 02:15:09 +01:00
//-----------------------------------------------------------------------------
// Console variables
//-----------------------------------------------------------------------------
static ConVar con_max_lines ( " con_max_lines " , " 1024 " , FCVAR_DEVELOPMENTONLY | FCVAR_MATERIAL_SYSTEM_THREAD , " Maximum number of lines in the console before cleanup starts " , true , 1.f , false , 0.f ) ;
static ConVar con_max_history ( " con_max_history " , " 512 " , FCVAR_DEVELOPMENTONLY | FCVAR_MATERIAL_SYSTEM_THREAD , " Maximum number of command submission items before history cleanup starts " , true , 0.f , false , 0.f ) ;
static ConVar con_suggest_limit ( " con_suggest_limit " , " 128 " , FCVAR_DEVELOPMENTONLY | FCVAR_MATERIAL_SYSTEM_THREAD , " Maximum number of suggestions the autocomplete window will show for the console " , true , 0.f , false , 0.f ) ;
static ConVar con_suggest_showhelptext ( " con_suggest_showhelptext " , " 1 " , FCVAR_DEVELOPMENTONLY | FCVAR_MATERIAL_SYSTEM_THREAD , " Show CommandBase help text in autocomplete window " ) ;
static ConVar con_suggest_showflags ( " con_suggest_showflags " , " 1 " , FCVAR_DEVELOPMENTONLY | FCVAR_MATERIAL_SYSTEM_THREAD , " Show CommandBase flags in autocomplete window " ) ;
//-----------------------------------------------------------------------------
// Console commands
//-----------------------------------------------------------------------------
2024-02-23 00:12:06 +01:00
static ConCommand toggleconsole ( " toggleconsole " , CConsole : : ToggleConsole_f , " Show/hide the developer console. " , FCVAR_CLIENTDLL | FCVAR_RELEASE ) ;
static ConCommand con_history ( " con_history " , CConsole : : LogHistory_f , " Shows the developer console submission history " , FCVAR_CLIENTDLL | FCVAR_RELEASE ) ;
static ConCommand con_removeline ( " con_removeline " , CConsole : : RemoveLine_f , " Removes a range of lines from the developer console " , FCVAR_CLIENTDLL | FCVAR_RELEASE ) ;
static ConCommand con_clearlines ( " con_clearlines " , CConsole : : ClearLines_f , " Clears all lines from the developer console " , FCVAR_CLIENTDLL | FCVAR_RELEASE ) ;
static ConCommand con_clearhistory ( " con_clearhistory " , CConsole : : ClearHistory_f , " Clears all submissions from the developer console history " , FCVAR_CLIENTDLL | FCVAR_RELEASE ) ;
2021-12-25 22:36:38 +01:00
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
2022-10-19 16:10:36 +02:00
CConsole : : CConsole ( void )
: m_pszConsoleLabel ( " Console " )
, m_pszLoggingLabel ( " LoggingRegion " )
2023-09-17 11:38:00 +02:00
, m_nHistoryPos ( PositionMode_t : : kPark )
, m_nSuggestPos ( PositionMode_t : : kPark )
2022-10-19 16:10:36 +02:00
, m_nScrollBack ( 0 )
, m_nSelectBack ( 0 )
2022-11-10 22:01:34 +01:00
, m_nInputTextLen ( 0 )
2022-10-19 16:10:36 +02:00
, m_flScrollX ( 0.f )
, m_flScrollY ( 0.f )
, m_flFadeAlpha ( 0.f )
, m_bInitialized ( false )
, m_bReclaimFocus ( false )
, m_bCopyToClipBoard ( false )
, m_bModifyInput ( false )
, m_bCanAutoComplete ( false )
, m_bSuggestActive ( false )
, m_bSuggestMoved ( false )
, m_bSuggestUpdate ( false )
, m_Style ( ImGuiStyle_t : : NONE )
2023-04-08 17:46:08 +02:00
, m_bActivate ( false )
2021-12-25 22:36:38 +01:00
{
2022-10-19 16:10:36 +02:00
m_nInputFlags =
ImGuiInputTextFlags_EnterReturnsTrue |
ImGuiInputTextFlags_CallbackCompletion |
ImGuiInputTextFlags_CallbackHistory |
ImGuiInputTextFlags_CallbackAlways |
2022-11-10 21:19:17 +01:00
ImGuiInputTextFlags_CallbackCharFilter |
2022-10-19 16:10:36 +02:00
ImGuiInputTextFlags_CallbackEdit |
ImGuiInputTextFlags_AutoCaretEnd ;
m_nSuggestFlags =
ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoFocusOnAppearing |
ImGuiWindowFlags_AlwaysVerticalScrollbar |
ImGuiWindowFlags_AlwaysHorizontalScrollbar ;
m_nLoggingFlags =
ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_HorizontalScrollbar |
ImGuiWindowFlags_AlwaysVerticalScrollbar ;
2021-12-25 22:36:38 +01:00
2022-10-19 16:10:36 +02:00
memset ( m_szInputBuf , ' \0 ' , sizeof ( m_szInputBuf ) ) ;
memset ( m_szWindowLabel , ' \0 ' , sizeof ( m_szWindowLabel ) ) ;
2022-06-26 16:47:00 +02:00
snprintf ( m_szSummary , sizeof ( m_szSummary ) , " %zu history items " , m_vHistory . size ( ) ) ;
2021-12-25 22:36:38 +01:00
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
2022-02-14 02:31:42 +01:00
CConsole : : ~ CConsole ( void )
2021-12-25 22:36:38 +01:00
{
2023-04-23 20:34:36 +02:00
for ( MODULERESOURCE & flagIcon : m_vFlagIcons )
{
if ( flagIcon . m_idIcon )
{
flagIcon . m_idIcon - > Release ( ) ;
}
}
2021-12-25 22:36:38 +01:00
}
2022-04-26 20:24:51 +02:00
//-----------------------------------------------------------------------------
// Purpose: game console setup
// Output : true on success, false otherwise
//-----------------------------------------------------------------------------
2022-08-14 15:43:49 +02:00
bool CConsole : : Init ( void )
2022-04-26 20:24:51 +02:00
{
SetStyleVar ( ) ;
2022-06-24 12:22:04 +02:00
return LoadFlagIcons ( ) ;
2022-04-26 20:24:51 +02:00
}
2021-12-25 22:36:38 +01:00
//-----------------------------------------------------------------------------
2022-01-17 23:20:03 +01:00
// Purpose: game console main render loop
2021-12-25 22:36:38 +01:00
//-----------------------------------------------------------------------------
2022-08-14 15:43:49 +02:00
void CConsole : : RunFrame ( void )
2021-12-25 22:36:38 +01:00
{
2022-10-20 12:29:21 +02:00
// Uncomment these when adjusting the theme or layout.
2022-01-19 19:00:40 +01:00
{
//ImGui::ShowStyleEditor();
//ImGui::ShowDemoWindow();
}
2021-12-25 22:36:38 +01:00
2022-01-28 12:56:51 +01:00
/**************************
* BASE PANEL SETUP *
* * * * * * * * * * * * * * * * * * * * * * * * * */
{
2022-10-20 12:29:21 +02:00
if ( ! m_bInitialized )
{
Init ( ) ;
m_bInitialized = true ;
}
int nVars = 0 ;
2023-01-30 01:59:25 +01:00
float flWidth ;
2023-01-30 01:52:32 +01:00
float flHeight ;
2022-08-22 01:10:18 +02:00
if ( m_Style = = ImGuiStyle_t : : MODERN )
2022-01-28 12:56:51 +01:00
{
2022-06-09 02:22:01 +02:00
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , ImVec2 { 8.f , 10.f } ) ; nVars + + ;
ImGui : : PushStyleVar ( ImGuiStyleVar_Alpha , m_flFadeAlpha ) ; nVars + + ;
2023-01-30 01:52:32 +01:00
2023-01-30 01:59:25 +01:00
flWidth = 621.f ;
2023-01-30 01:52:32 +01:00
flHeight = 532.f ;
2022-01-28 12:56:51 +01:00
}
else
{
2023-01-30 01:52:32 +01:00
if ( m_Style = = ImGuiStyle_t : : LEGACY )
{
2023-01-30 01:59:25 +01:00
flWidth = 619.f ;
2023-01-30 01:52:32 +01:00
flHeight = 526.f ;
}
else
{
2023-01-30 01:59:25 +01:00
flWidth = 618.f ;
2023-01-30 01:52:32 +01:00
flHeight = 524.f ;
}
2022-06-24 12:45:47 +02:00
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , ImVec2 { 6.f , 6.f } ) ; nVars + + ;
2022-06-09 02:22:01 +02:00
ImGui : : PushStyleVar ( ImGuiStyleVar_Alpha , m_flFadeAlpha ) ; nVars + + ;
2022-01-28 12:56:51 +01:00
}
2023-01-30 01:59:25 +01:00
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowMinSize , ImVec2 ( flWidth , flHeight ) ) ; nVars + + ;
2022-01-17 23:20:03 +01:00
2022-08-14 15:43:49 +02:00
DrawSurface ( ) ;
2022-02-06 16:33:11 +01:00
ImGui : : PopStyleVar ( nVars ) ;
2022-01-17 23:20:03 +01:00
}
2022-01-28 12:56:51 +01:00
/**************************
* SUGGESTION PANEL SETUP *
* * * * * * * * * * * * * * * * * * * * * * * * * */
{
2022-06-18 18:11:05 +02:00
int nVars = 0 ;
2022-06-22 03:24:46 +02:00
if ( AutoComplete ( ) )
2022-01-17 23:20:03 +01:00
{
2022-08-22 01:10:18 +02:00
if ( m_Style = = ImGuiStyle_t : : MODERN )
2022-01-28 12:56:51 +01:00
{
2023-06-17 16:30:10 +02:00
const ImGuiStyle & style = ImGui : : GetStyle ( ) ;
2022-05-27 16:28:37 +02:00
m_ivSuggestWindowPos . y = m_ivSuggestWindowPos . y + style . WindowPadding . y + 1.5f ;
2022-01-28 12:56:51 +01:00
}
2022-05-27 16:28:37 +02:00
ImGui : : SetNextWindowPos ( m_ivSuggestWindowPos ) ;
ImGui : : SetNextWindowSize ( m_ivSuggestWindowSize ) ;
2022-06-26 16:47:00 +02:00
if ( m_bSuggestUpdate )
{
ImGui : : SetNextWindowScroll ( ImVec2 ( 0.f , 0.f ) ) ;
m_bSuggestUpdate = false ;
}
2022-01-19 19:00:40 +01:00
2022-06-14 22:37:43 +02:00
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowMinSize , ImVec2 ( 500 , 37 ) ) ; nVars + + ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowBorderSize , 1.0f ) ; nVars + + ;
ImGui : : PushStyleVar ( ImGuiStyleVar_Alpha , m_flFadeAlpha ) ; nVars + + ;
2022-01-19 19:00:40 +01:00
2022-01-17 23:20:03 +01:00
SuggestPanel ( ) ;
2022-01-19 19:00:40 +01:00
2022-02-06 16:33:11 +01:00
ImGui : : PopStyleVar ( nVars ) ;
2022-01-17 23:20:03 +01:00
}
}
}
2021-12-25 22:36:38 +01:00
2022-01-17 23:20:03 +01:00
//-----------------------------------------------------------------------------
2022-08-20 01:48:42 +02:00
// Purpose: runs tasks for the console while not being drawn
// (!!! RunTask and RunFrame must be called from the same thread !!!)
2022-01-17 23:20:03 +01:00
//-----------------------------------------------------------------------------
2022-10-24 00:50:07 +02:00
void CConsole : : RunTask ( void )
2022-01-17 23:20:03 +01:00
{
2022-10-19 16:10:36 +02:00
// m_Logger and m_vHistory are modified.
2024-01-21 23:06:26 +01:00
AUTO_LOCK ( m_Mutex ) ;
2022-10-19 16:10:36 +02:00
2022-08-22 01:10:18 +02:00
ClampLogSize ( ) ;
ClampHistorySize ( ) ;
2022-08-20 01:48:42 +02:00
}
2022-06-09 02:22:01 +02:00
2022-08-20 01:48:42 +02:00
//-----------------------------------------------------------------------------
// Purpose: think
//-----------------------------------------------------------------------------
void CConsole : : Think ( void )
{
2022-08-29 02:21:32 +02:00
if ( m_bActivate )
2022-08-20 01:48:42 +02:00
{
2022-10-18 02:11:52 +02:00
if ( m_flFadeAlpha < 1.f )
2022-06-09 02:22:01 +02:00
{
2023-04-16 02:45:22 +02:00
m_flFadeAlpha + = .05f ;
m_flFadeAlpha = ( std : : min ) ( m_flFadeAlpha , 1.f ) ;
2022-06-09 02:22:01 +02:00
}
2022-08-29 02:21:32 +02:00
}
else // Reset to full transparent.
{
2023-04-16 02:45:22 +02:00
if ( m_flFadeAlpha > 0.f )
{
m_flFadeAlpha - = .05f ;
m_flFadeAlpha = ( std : : max ) ( m_flFadeAlpha , 0.f ) ;
}
2022-08-29 02:21:32 +02:00
m_bReclaimFocus = true ;
2022-06-09 02:22:01 +02:00
}
2022-01-17 23:20:03 +01:00
}
//-----------------------------------------------------------------------------
// Purpose: draws the console's main surface
2022-02-14 02:31:42 +01:00
// Input : *bDraw -
2022-01-17 23:20:03 +01:00
//-----------------------------------------------------------------------------
2022-08-14 15:43:49 +02:00
void CConsole : : DrawSurface ( void )
2022-01-17 23:20:03 +01:00
{
2022-10-20 01:17:51 +02:00
if ( ! ImGui : : Begin ( m_pszConsoleLabel , & m_bActivate , ImGuiWindowFlags_None , & ResetInput ) )
2021-12-25 22:36:38 +01:00
{
2022-01-17 23:20:03 +01:00
ImGui : : End ( ) ;
return ;
2021-12-25 22:36:38 +01:00
}
2023-06-17 16:30:10 +02:00
const ImGuiStyle & style = ImGui : : GetStyle ( ) ;
2021-12-25 22:36:38 +01:00
// Reserve enough left-over height and width for 1 separator + 1 input text
2023-06-17 16:30:10 +02:00
const float flFooterHeightReserve = style . ItemSpacing . y + ImGui : : GetFrameHeightWithSpacing ( ) ;
const float flFooterWidthReserve = style . ItemSpacing . y + ImGui : : GetWindowWidth ( ) ;
2021-12-25 22:36:38 +01:00
2022-06-22 03:24:46 +02:00
ImVec2 fontSize = ImGui : : GetFont ( ) - > CalcTextSizeA ( ImGui : : GetFontSize ( ) , FLT_MAX , - 1.0f , " # " , nullptr , nullptr ) ;
2021-12-25 22:36:38 +01:00
///////////////////////////////////////////////////////////////////////
ImGui : : Separator ( ) ;
if ( ImGui : : BeginPopup ( " Options " ) )
{
2022-01-17 23:20:03 +01:00
OptionsPanel ( ) ;
2021-12-25 22:36:38 +01:00
}
if ( ImGui : : Button ( " Options " ) )
{
ImGui : : OpenPopup ( " Options " ) ;
}
2022-01-12 02:53:07 +01:00
2021-12-25 22:36:38 +01:00
ImGui : : SameLine ( ) ;
2023-04-09 22:35:55 +02:00
m_Logger . GetFilter ( ) . Draw ( " Filter | " , flFooterWidthReserve - 500 ) ;
2022-01-28 12:56:51 +01:00
ImGui : : SameLine ( ) ;
2023-04-08 19:10:59 +02:00
ImGui : : Text ( " %s " , m_szSummary ) ;
2022-01-28 12:56:51 +01:00
2021-12-25 22:36:38 +01:00
ImGui : : Separator ( ) ;
///////////////////////////////////////////////////////////////////////
2023-04-09 22:35:55 +02:00
if ( ! m_Logger . IsScrolledToBottom ( ) & & m_nScrollBack > 0 )
2022-06-26 16:47:00 +02:00
{
ImGuiWindow * pWindow = ImGui : : GetCurrentWindow ( ) ;
ImGuiID nID = pWindow - > GetID ( m_pszLoggingLabel ) ;
snprintf ( m_szWindowLabel , sizeof ( m_szWindowLabel ) , " %s/%s_%08X " , m_pszConsoleLabel , m_pszLoggingLabel , nID ) ;
ImGui : : SetWindowScrollY ( m_szWindowLabel , m_flScrollY - m_nScrollBack * fontSize . y ) ;
}
m_nScrollBack = 0 ;
///////////////////////////////////////////////////////////////////////
2023-01-30 01:52:32 +01:00
int iVars = 0 ; // Eliminate borders around log window.
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , ImVec2 { 1.f , 1.f } ) ; iVars + + ;
2022-06-26 16:47:00 +02:00
ImGui : : BeginChild ( m_pszLoggingLabel , ImVec2 ( 0 , - flFooterHeightReserve ) , true , m_nLoggingFlags ) ;
2022-08-22 01:10:18 +02:00
2022-10-19 16:10:36 +02:00
// Mutex is locked here, as we start using/modifying
// non-atomic members that are used from several threads.
2024-01-21 23:06:26 +01:00
AUTO_LOCK ( m_Mutex ) ;
2022-06-20 10:31:09 +02:00
m_Logger . Render ( ) ;
2022-01-12 02:53:07 +01:00
if ( m_bCopyToClipBoard )
2021-12-25 22:36:38 +01:00
{
2022-06-21 23:25:15 +02:00
m_Logger . Copy ( true ) ;
2022-01-12 02:53:07 +01:00
m_bCopyToClipBoard = false ;
2021-12-25 22:36:38 +01:00
}
2022-06-26 16:47:00 +02:00
m_flScrollX = ImGui : : GetScrollX ( ) ;
m_flScrollY = ImGui : : GetScrollY ( ) ;
2022-01-22 15:51:09 +01:00
2021-12-25 22:36:38 +01:00
ImGui : : EndChild ( ) ;
2023-01-30 01:52:32 +01:00
ImGui : : PopStyleVar ( iVars ) ;
2021-12-25 22:36:38 +01:00
ImGui : : Separator ( ) ;
2023-02-06 21:43:43 +01:00
std : : function < void ( void ) > fnHandleInput = [ & ] ( void )
{
if ( m_szInputBuf [ 0 ] )
{
ProcessCommand ( m_szInputBuf ) ;
2023-09-17 16:15:42 +02:00
ResetAutoComplete ( ) ;
2023-02-06 21:43:43 +01:00
m_bModifyInput = true ;
}
BuildSummary ( ) ;
m_bReclaimFocus = true ;
} ;
2022-10-19 16:10:36 +02:00
///////////////////////////////////////////////////////////////////////
2022-06-18 18:11:05 +02:00
ImGui : : PushItemWidth ( flFooterWidthReserve - 80 ) ;
2022-05-27 16:28:37 +02:00
if ( ImGui : : InputText ( " ##input " , m_szInputBuf , IM_ARRAYSIZE ( m_szInputBuf ) , m_nInputFlags , & TextEditCallbackStub , reinterpret_cast < void * > ( this ) ) )
2021-12-25 22:36:38 +01:00
{
2023-09-17 11:38:00 +02:00
if ( m_nSuggestPos > PositionMode_t : : kPark )
2022-01-17 23:20:03 +01:00
{
2023-02-05 19:21:39 +01:00
BuildInputFromSelected ( m_vSuggest [ m_nSuggestPos ] , m_svInputConVar ) ;
2023-02-06 21:43:43 +01:00
BuildSummary ( m_svInputConVar ) ;
2021-12-25 22:36:38 +01:00
2023-02-06 21:43:43 +01:00
m_bModifyInput = true ;
2023-02-06 00:04:08 +01:00
m_bReclaimFocus = true ;
2022-01-17 23:20:03 +01:00
}
else
{
2023-02-06 21:43:43 +01:00
fnHandleInput ( ) ;
2022-01-17 23:20:03 +01:00
}
2021-12-25 22:36:38 +01:00
}
2022-10-20 01:17:51 +02:00
// Auto-focus input field on window apparition.
ImGui : : SetItemDefaultFocus ( ) ;
2021-12-25 22:36:38 +01:00
2022-10-20 01:17:51 +02:00
// Auto-focus input field if reclaim is demanded.
2022-01-12 02:53:07 +01:00
if ( m_bReclaimFocus )
2021-12-25 22:36:38 +01:00
{
2022-10-20 01:17:51 +02:00
ImGui : : SetKeyboardFocusHere ( - 1 ) ; // -1 means previous widget.
2022-01-12 02:53:07 +01:00
m_bReclaimFocus = false ;
2021-12-25 22:36:38 +01:00
}
2022-08-31 13:00:02 +02:00
BuildSuggestPanelRect ( ) ;
2022-01-17 23:20:03 +01:00
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( " Submit " ) )
{
2023-02-06 21:43:43 +01:00
fnHandleInput ( ) ;
2022-01-17 23:20:03 +01:00
}
2021-12-25 22:36:38 +01:00
ImGui : : End ( ) ;
}
2022-01-12 02:53:07 +01:00
//-----------------------------------------------------------------------------
// Purpose: draws the options panel
//-----------------------------------------------------------------------------
2022-01-17 23:20:03 +01:00
void CConsole : : OptionsPanel ( void )
2022-01-12 02:53:07 +01:00
{
2023-01-28 14:21:18 +01:00
ImGui : : Checkbox ( " Auto-scroll " , & m_Logger . m_bAutoScroll ) ;
2022-01-12 02:53:07 +01:00
ImGui : : SameLine ( ) ;
ImGui : : PushItemWidth ( 100 ) ;
ImGui : : PopItemWidth ( ) ;
if ( ImGui : : SmallButton ( " Clear " ) )
{
ClearLog ( ) ;
}
ImGui : : SameLine ( ) ;
m_bCopyToClipBoard = ImGui : : SmallButton ( " Copy " ) ;
2023-01-28 14:21:18 +01:00
ImGui : : Text ( " Console hotkey: " ) ;
2022-01-12 02:53:07 +01:00
ImGui : : SameLine ( ) ;
2022-10-20 12:29:21 +02:00
if ( ImGui : : Hotkey ( " ##ToggleConsole " , & g_pImGuiConfig - > m_ConsoleConfig . m_nBind0 , ImVec2 ( 80 , 80 ) ) )
2022-01-12 02:53:07 +01:00
{
g_pImGuiConfig - > Save ( ) ;
}
2023-01-28 14:21:18 +01:00
ImGui : : Text ( " Browser hotkey: " ) ;
2022-01-12 02:53:07 +01:00
ImGui : : SameLine ( ) ;
2022-10-20 12:29:21 +02:00
if ( ImGui : : Hotkey ( " ##ToggleBrowser " , & g_pImGuiConfig - > m_BrowserConfig . m_nBind0 , ImVec2 ( 80 , 80 ) ) )
2022-01-12 02:53:07 +01:00
{
g_pImGuiConfig - > Save ( ) ;
}
ImGui : : EndPopup ( ) ;
}
2022-01-16 00:59:20 +01:00
//-----------------------------------------------------------------------------
2022-01-17 23:20:03 +01:00
// Purpose: draws the suggestion panel with results based on user input
2022-01-16 00:59:20 +01:00
//-----------------------------------------------------------------------------
2022-01-17 23:20:03 +01:00
void CConsole : : SuggestPanel ( void )
2022-01-16 00:59:20 +01:00
{
2022-05-27 16:28:37 +02:00
ImGui : : Begin ( " ##suggest " , nullptr , m_nSuggestFlags ) ;
2022-01-17 23:20:03 +01:00
ImGui : : PushAllowKeyboardFocus ( false ) ;
2022-10-20 15:22:20 +02:00
for ( size_t i = 0 , ns = m_vSuggest . size ( ) ; i < ns ; i + + )
2022-01-16 00:59:20 +01:00
{
2022-10-20 15:22:20 +02:00
const CSuggest & suggest = m_vSuggest [ i ] ;
2023-04-02 12:09:43 +02:00
const bool bIsIndexActive = m_nSuggestPos = = ssize_t ( i ) ;
2022-10-20 15:22:20 +02:00
2022-08-21 19:35:06 +02:00
ImGui : : PushID ( static_cast < int > ( i ) ) ;
2022-04-26 20:24:51 +02:00
2024-02-24 02:15:09 +01:00
if ( con_suggest_showflags . GetBool ( ) )
2022-04-26 20:24:51 +02:00
{
2022-12-29 13:30:33 +01:00
// Show the flag texture before the cvar name.
const int mainTexIdx = GetFlagTextureIndex ( suggest . m_nFlags ) ;
const MODULERESOURCE & mainRes = m_vFlagIcons [ mainTexIdx ] ;
2023-04-02 00:59:24 +02:00
ImGui : : Image ( mainRes . m_idIcon , ImVec2 ( float ( mainRes . m_nWidth ) , float ( mainRes . m_nHeight ) ) ) ;
2022-12-29 13:30:33 +01:00
// Show a more detailed description of the flag when user hovers over the texture.
2023-02-05 19:21:39 +01:00
if ( ImGui : : IsItemHovered ( ImGuiHoveredFlags_RectOnly ) & &
suggest . m_nFlags ! = COMMAND_COMPLETION_MARKER )
2022-12-29 13:30:33 +01:00
{
2023-07-03 13:48:13 +02:00
std : : function < void ( const ConVarFlags : : FlagDesc_t & ) > fnAddHint = [ & ] ( const ConVarFlags : : FlagDesc_t & cvarInfo )
2022-12-29 13:30:33 +01:00
{
2023-07-03 13:48:13 +02:00
const int hintTexIdx = GetFlagTextureIndex ( cvarInfo . bit ) ;
2022-12-29 13:30:33 +01:00
const MODULERESOURCE & hintRes = m_vFlagIcons [ hintTexIdx ] ;
2023-04-02 00:59:24 +02:00
ImGui : : Image ( hintRes . m_idIcon , ImVec2 ( float ( hintRes . m_nWidth ) , float ( hintRes . m_nHeight ) ) ) ;
2022-12-29 13:30:33 +01:00
ImGui : : SameLine ( ) ;
2023-07-03 13:48:13 +02:00
ImGui : : Text ( " %s " , cvarInfo . shortdesc ) ;
2022-12-29 13:30:33 +01:00
} ;
ImGui : : BeginTooltip ( ) ;
bool bFlagSet = false ;
// Reverse loop to display the most significant flag first.
2023-07-03 13:48:13 +02:00
for ( int j = IM_ARRAYSIZE ( g_ConVarFlags . m_FlagsToDesc ) ; ( j - - ) > 0 ; )
2022-12-29 13:30:33 +01:00
{
2023-07-03 13:48:13 +02:00
const ConVarFlags : : FlagDesc_t & info = g_ConVarFlags . m_FlagsToDesc [ j ] ;
if ( suggest . m_nFlags & info . bit )
2022-12-29 13:30:33 +01:00
{
bFlagSet = true ;
fnAddHint ( info ) ;
}
}
if ( ! bFlagSet ) // Display the FCVAR_NONE flag if no flags are set.
{
2023-07-03 13:48:13 +02:00
fnAddHint ( g_ConVarFlags . m_FlagsToDesc [ 0 ] ) ;
2022-12-29 13:30:33 +01:00
}
ImGui : : EndTooltip ( ) ;
}
2022-04-26 20:24:51 +02:00
ImGui : : SameLine ( ) ;
}
2022-10-20 15:22:20 +02:00
if ( ImGui : : Selectable ( suggest . m_svName . c_str ( ) , bIsIndexActive ) )
2022-01-16 00:59:20 +01:00
{
2022-01-17 23:20:03 +01:00
ImGui : : Separator ( ) ;
2023-02-05 19:21:39 +01:00
string svConVar ;
2022-01-17 23:20:03 +01:00
2023-02-06 21:43:43 +01:00
BuildInputFromSelected ( suggest , svConVar ) ;
2022-10-19 16:10:36 +02:00
memmove ( m_szInputBuf , svConVar . data ( ) , svConVar . size ( ) + 1 ) ;
2023-02-06 02:12:53 +01:00
m_bCanAutoComplete = true ;
2023-02-06 00:04:08 +01:00
m_bReclaimFocus = true ;
2022-10-19 16:10:36 +02:00
2022-06-22 03:24:46 +02:00
BuildSummary ( svConVar ) ;
2022-01-16 00:59:20 +01:00
}
2023-09-17 01:25:44 +02:00
2022-01-17 23:20:03 +01:00
ImGui : : PopID ( ) ;
2023-09-17 01:25:44 +02:00
// Update the suggest position
2023-09-17 12:06:38 +02:00
if ( m_bSuggestMoved )
2022-01-16 00:59:20 +01:00
{
2023-09-17 01:25:44 +02:00
if ( bIsIndexActive ) // Bring the 'active' element into view
{
2023-09-17 12:06:38 +02:00
ImGuiWindow * const pWindow = ImGui : : GetCurrentWindow ( ) ;
ImRect imRect = ImGui : : GetCurrentContext ( ) - > LastItemData . Rect ;
2023-09-17 01:25:44 +02:00
// Reset to keep flag in display.
imRect . Min . x = pWindow - > InnerRect . Min . x ;
2023-09-17 12:06:38 +02:00
imRect . Max . x = pWindow - > InnerRect . Max . x ;
2023-09-17 01:25:44 +02:00
// Eliminate jiggle when going up/down in the menu.
imRect . Min . y + = 1 ;
imRect . Max . y - = 1 ;
2022-04-26 20:24:51 +02:00
2023-09-17 12:06:38 +02:00
ImGui : : ScrollToRect ( pWindow , imRect ) ;
m_bSuggestMoved = false ;
2023-09-17 01:25:44 +02:00
}
2023-09-17 12:06:38 +02:00
else if ( m_nSuggestPos = = PositionMode_t : : kPark )
2023-09-17 01:25:44 +02:00
{
2023-09-17 12:06:38 +02:00
// Reset position; kPark = no active element.
ImGui : : SetScrollX ( 0.0f ) ;
ImGui : : SetScrollY ( 0.0f ) ;
2023-09-17 01:25:44 +02:00
2023-09-17 12:06:38 +02:00
m_bSuggestMoved = false ;
2023-09-17 01:25:44 +02:00
}
2022-01-16 00:59:20 +01:00
}
}
2022-01-17 23:20:03 +01:00
ImGui : : PopAllowKeyboardFocus ( ) ;
ImGui : : End ( ) ;
}
//-----------------------------------------------------------------------------
2022-11-10 21:19:17 +01:00
// Purpose: runs the auto complete for the console
// Output : true if auto complete is performed, false otherwise
2022-01-17 23:20:03 +01:00
//-----------------------------------------------------------------------------
2022-06-22 03:24:46 +02:00
bool CConsole : : AutoComplete ( void )
2022-01-17 23:20:03 +01:00
{
2023-02-05 19:21:39 +01:00
// Don't suggest if user tries to assign value to ConVar or execute ConCommand.
if ( ! m_szInputBuf [ 0 ] | | strstr ( m_szInputBuf , " ; " ) )
{
2023-02-05 22:50:11 +01:00
if ( m_bSuggestActive )
{
2023-09-17 16:15:42 +02:00
ResetAutoComplete ( ) ;
2023-02-05 22:50:11 +01:00
}
2023-02-05 19:21:39 +01:00
return false ;
}
if ( ! strstr ( m_szInputBuf , " " ) )
2022-01-17 23:20:03 +01:00
{
2022-06-22 03:24:46 +02:00
if ( m_bCanAutoComplete )
2022-01-17 23:20:03 +01:00
{
FindFromPartial ( ) ;
}
}
2023-02-05 21:10:39 +01:00
else if ( m_bCanAutoComplete ) // Command completion callback.
2022-01-17 23:20:03 +01:00
{
2023-09-17 16:15:42 +02:00
ResetAutoComplete ( ) ;
2022-09-07 01:55:52 +02:00
2024-02-23 00:12:06 +01:00
char szCommand [ sizeof ( m_szInputBuf ) ] ;
size_t i = 0 ;
// Truncate everything past (and including) the space to get the
// command string.
for ( ; i < sizeof ( m_szInputBuf ) ; i + + )
2023-02-05 19:21:39 +01:00
{
if ( isspace ( m_szInputBuf [ i ] ) )
{
break ;
}
2024-02-23 00:12:06 +01:00
szCommand [ i ] = m_szInputBuf [ i ] ;
2023-02-05 19:21:39 +01:00
}
2022-01-17 23:20:03 +01:00
2024-02-23 00:12:06 +01:00
szCommand [ i ] = ' \0 ' ;
ConCommand * pCommand = g_pCVar - > FindCommand ( szCommand ) ;
2022-08-28 17:28:53 +02:00
2023-03-17 00:17:35 +01:00
if ( pCommand & & pCommand - > CanAutoComplete ( ) )
{
CUtlVector < CUtlString > commands ;
2023-03-17 19:24:54 +01:00
int iret = pCommand - > AutoCompleteSuggest ( m_szInputBuf , commands ) ;
2023-02-05 19:21:39 +01:00
if ( ! iret )
{
return false ;
}
2024-02-23 00:12:06 +01:00
for ( int j = 0 ; j < iret ; + + j )
2023-02-05 19:21:39 +01:00
{
2024-02-23 00:12:06 +01:00
m_vSuggest . push_back ( CSuggest ( commands [ j ] . String ( ) , COMMAND_COMPLETION_MARKER ) ) ;
2023-02-05 19:21:39 +01:00
}
}
else
{
return false ;
}
2022-01-17 23:20:03 +01:00
}
2023-02-05 19:21:39 +01:00
2023-02-05 21:10:39 +01:00
if ( m_vSuggest . empty ( ) )
{
return false ;
}
2022-01-17 23:20:03 +01:00
m_bSuggestActive = true ;
return true ;
}
2022-03-25 13:31:31 +01:00
//-----------------------------------------------------------------------------
2022-11-10 21:19:17 +01:00
// Purpose: resets the auto complete window
2022-03-25 13:31:31 +01:00
//-----------------------------------------------------------------------------
void CConsole : : ResetAutoComplete ( void )
{
2023-09-17 16:15:42 +02:00
m_nSuggestPos = PositionMode_t : : kPark ;
2023-09-17 12:47:36 +02:00
m_bCanAutoComplete = false ;
2022-03-25 13:31:31 +01:00
m_bSuggestActive = false ;
2023-09-17 01:37:01 +02:00
m_bSuggestMoved = true ;
2022-06-22 03:24:46 +02:00
m_vSuggest . clear ( ) ;
2022-06-18 18:11:05 +02:00
}
//-----------------------------------------------------------------------------
// Purpose: find ConVars/ConCommands from user input and add to vector
2022-10-20 12:29:21 +02:00
// - Ignores ConVars marked FCVAR_HIDDEN
2022-06-18 18:11:05 +02:00
//-----------------------------------------------------------------------------
void CConsole : : FindFromPartial ( void )
{
2023-09-17 16:15:42 +02:00
ResetAutoComplete ( ) ;
2022-01-18 11:23:14 +01:00
2023-07-22 14:51:15 +02:00
ICvar : : Iterator iter ( g_pCVar ) ;
for ( iter . SetFirst ( ) ; iter . IsValid ( ) ; iter . Next ( ) )
2022-01-17 23:20:03 +01:00
{
2024-02-24 02:15:09 +01:00
if ( m_vSuggest . size ( ) > = con_suggest_limit . GetInt ( ) )
2022-01-17 23:20:03 +01:00
{
2023-07-22 14:51:15 +02:00
break ;
2022-10-07 22:31:16 +02:00
}
2023-07-22 14:51:15 +02:00
const ConCommandBase * pCommandBase = iter . Get ( ) ;
if ( pCommandBase - > IsFlagSet ( FCVAR_HIDDEN ) )
2022-10-07 22:31:16 +02:00
{
continue ;
}
2023-07-22 14:51:15 +02:00
const char * pCommandName = pCommandBase - > GetName ( ) ;
if ( ! V_stristr ( pCommandName , m_szInputBuf ) )
2022-10-07 22:31:16 +02:00
{
2023-07-22 14:51:15 +02:00
continue ;
}
2022-10-07 22:31:16 +02:00
2023-07-22 14:51:15 +02:00
if ( std : : find ( m_vSuggest . begin ( ) , m_vSuggest . end ( ) ,
pCommandName ) = = m_vSuggest . end ( ) )
{
string svValue ;
2022-02-23 15:56:03 +01:00
2022-10-07 22:31:16 +02:00
if ( ! pCommandBase - > IsCommand ( ) )
{
2022-10-11 01:22:21 +02:00
const ConVar * pConVar = reinterpret_cast < const ConVar * > ( pCommandBase ) ;
2022-10-07 22:31:16 +02:00
svValue = " = [ " ; // Assign default value to string if its a ConVar.
svValue . append ( pConVar - > GetString ( ) ) ;
svValue . append ( " ] " ) ;
}
2024-02-24 02:15:09 +01:00
if ( con_suggest_showhelptext . GetBool ( ) )
2022-10-07 22:31:16 +02:00
{
2023-08-08 02:21:33 +02:00
std : : function < void ( string & , const char * ) > fnAppendDocString = [ & ] ( string & svTarget , const char * pszDocString )
2022-10-07 22:31:16 +02:00
{
2023-08-08 02:21:33 +02:00
if ( VALID_CHARSTAR ( pszDocString ) )
2022-10-07 22:31:16 +02:00
{
2023-08-08 02:21:33 +02:00
svTarget . append ( " - \" " ) ;
svTarget . append ( pszDocString ) ;
svTarget . append ( " \" " ) ;
2022-10-07 22:31:16 +02:00
}
2023-08-08 02:21:33 +02:00
} ;
fnAppendDocString ( svValue , pCommandBase - > GetHelpText ( ) ) ;
fnAppendDocString ( svValue , pCommandBase - > GetUsageText ( ) ) ;
2022-01-17 23:20:03 +01:00
}
2023-07-22 14:51:15 +02:00
m_vSuggest . push_back ( CSuggest ( pCommandName + svValue , pCommandBase - > GetFlags ( ) ) ) ;
2022-01-17 23:20:03 +01:00
}
else { break ; }
}
2022-10-19 16:10:36 +02:00
2022-06-22 03:24:46 +02:00
std : : sort ( m_vSuggest . begin ( ) , m_vSuggest . end ( ) ) ;
2022-01-16 00:59:20 +01:00
}
2021-12-25 22:36:38 +01:00
//-----------------------------------------------------------------------------
2022-08-21 19:35:06 +02:00
// Purpose: processes submitted commands for the main thread
2022-10-20 12:29:21 +02:00
// Input : svCommand -
2021-12-25 22:36:38 +01:00
//-----------------------------------------------------------------------------
2022-10-20 12:29:21 +02:00
void CConsole : : ProcessCommand ( string svCommand )
2021-12-25 22:36:38 +01:00
{
2022-10-20 12:29:21 +02:00
StringRTrim ( svCommand , " " ) ; // Remove trailing white space characters to prevent history duplication.
AddLog ( ImVec4 ( 1.00f , 0.80f , 0.60f , 1.00f ) , " %s] %s \n " , Plat_GetProcessUpTime ( ) , svCommand . c_str ( ) ) ;
2021-12-25 22:36:38 +01:00
2022-10-20 12:29:21 +02:00
Cbuf_AddText ( Cbuf_GetCurrentPlayer ( ) , svCommand . c_str ( ) , cmd_source_t : : kCommandSrcCode ) ;
2023-09-17 11:38:00 +02:00
m_nHistoryPos = PositionMode_t : : kPark ;
2022-10-20 12:29:21 +02:00
2022-10-19 16:10:36 +02:00
for ( size_t i = m_vHistory . size ( ) ; i - - > 0 ; )
2021-12-25 22:36:38 +01:00
{
2022-10-20 12:29:21 +02:00
if ( m_vHistory [ i ] . compare ( svCommand ) = = 0 )
2021-12-25 22:36:38 +01:00
{
2022-06-22 03:24:46 +02:00
m_vHistory . erase ( m_vHistory . begin ( ) + i ) ;
2021-12-25 22:36:38 +01:00
break ;
}
}
2022-10-20 15:07:40 +02:00
m_vHistory . push_back ( svCommand ) ;
2023-04-09 22:35:55 +02:00
m_Logger . ShouldScrollToBottom ( true ) ;
2021-12-25 22:36:38 +01:00
}
2022-06-24 12:22:04 +02:00
//-----------------------------------------------------------------------------
// Purpose: builds the console summary
// Input : svConVar -
//-----------------------------------------------------------------------------
void CConsole : : BuildSummary ( string svConVar )
{
if ( ! svConVar . empty ( ) )
{
2022-10-24 00:50:07 +02:00
// Remove trailing space and/or semicolon before we call 'g_pCVar->FindVar(..)'.
2022-11-11 01:19:49 +01:00
StringRTrim ( svConVar , " ; " , true ) ;
2023-10-15 10:41:17 +02:00
const ConVar * const pConVar = g_pCVar - > FindVar ( svConVar . c_str ( ) ) ;
2022-06-24 12:22:04 +02:00
2023-10-15 10:41:17 +02:00
if ( pConVar & & ! pConVar - > IsFlagSet ( FCVAR_HIDDEN ) )
2022-06-24 12:22:04 +02:00
{
// Display the current and default value of ConVar if found.
snprintf ( m_szSummary , sizeof ( m_szSummary ) , " ( \" %s \" , default \" %s \" ) " , pConVar - > GetString ( ) , pConVar - > GetDefault ( ) ) ;
2022-10-20 12:29:21 +02:00
return ;
2022-06-24 12:22:04 +02:00
}
}
2023-02-06 21:43:43 +01:00
2022-10-20 12:29:21 +02:00
snprintf ( m_szSummary , sizeof ( m_szSummary ) , " %zu history items " , m_vHistory . size ( ) ) ;
2022-06-24 12:22:04 +02:00
}
2023-02-05 19:21:39 +01:00
//-----------------------------------------------------------------------------
// Purpose: builds the selected suggestion for input field
// Input : &suggest -
//-----------------------------------------------------------------------------
void CConsole : : BuildInputFromSelected ( const CSuggest & suggest , string & svInput )
{
if ( suggest . m_nFlags = = COMMAND_COMPLETION_MARKER )
{
svInput = suggest . m_svName + ' ' ;
}
else // Remove the default value from ConVar before assigning it to the input buffer.
{
svInput = suggest . m_svName . substr ( 0 , suggest . m_svName . find ( ' ' ) ) + ' ' ;
}
}
2022-08-31 13:00:02 +02:00
//-----------------------------------------------------------------------------
// Purpose: builds the suggestion panel rect
//-----------------------------------------------------------------------------
void CConsole : : BuildSuggestPanelRect ( void )
{
float flSinglePadding = 0.f ;
2022-10-19 16:10:36 +02:00
const float flItemHeight = ImGui : : GetTextLineHeightWithSpacing ( ) + 1.0f ;
2022-08-31 13:00:02 +02:00
if ( m_vSuggest . size ( ) > 1 )
{
// Pad with 18 to keep all items in view.
flSinglePadding = flItemHeight ;
}
m_ivSuggestWindowPos = ImGui : : GetItemRectMin ( ) ;
m_ivSuggestWindowPos . y + = ImGui : : GetItemRectSize ( ) . y ;
2022-10-19 16:10:36 +02:00
const float flWindowHeight = ( flSinglePadding + std : : clamp (
static_cast < float > ( m_vSuggest . size ( ) ) * ( flItemHeight ) , 37.0f , 127.5f ) ) ;
2022-08-31 13:00:02 +02:00
m_ivSuggestWindowSize = ImVec2 ( 600 , flWindowHeight ) ;
}
2022-08-22 01:10:18 +02:00
//-----------------------------------------------------------------------------
// Purpose: clamps the size of the log vector
//-----------------------------------------------------------------------------
void CConsole : : ClampLogSize ( void )
{
2024-02-24 02:15:09 +01:00
const int nMaxLines = con_max_lines . GetInt ( ) ;
2022-10-19 16:10:36 +02:00
if ( m_Logger . GetTotalLines ( ) > nMaxLines )
2022-08-22 01:10:18 +02:00
{
2022-10-19 16:10:36 +02:00
while ( m_Logger . GetTotalLines ( ) > nMaxLines )
2022-08-22 01:10:18 +02:00
{
m_Logger . RemoveLine ( 0 ) ;
m_nScrollBack + + ;
m_nSelectBack + + ;
}
m_Logger . MoveSelection ( m_nSelectBack , false ) ;
m_Logger . MoveCursor ( m_nSelectBack , false ) ;
m_nSelectBack = 0 ;
}
}
//-----------------------------------------------------------------------------
// Purpose: clamps the size of the history vector
//-----------------------------------------------------------------------------
void CConsole : : ClampHistorySize ( void )
{
2024-02-24 02:15:09 +01:00
while ( m_vHistory . size ( ) > con_max_history . GetInt ( ) )
2022-08-22 01:10:18 +02:00
{
m_vHistory . erase ( m_vHistory . begin ( ) ) ;
}
}
2022-06-24 12:22:04 +02:00
//-----------------------------------------------------------------------------
// Purpose: loads flag images from resource section (must be aligned with resource.h!)
// Output : true on success, false on failure
//-----------------------------------------------------------------------------
bool CConsole : : LoadFlagIcons ( void )
{
2022-10-19 16:10:36 +02:00
bool ret = false ;
2022-11-11 20:12:20 +01:00
// Get all flag image resources for displaying flags.
2023-02-05 19:21:39 +01:00
for ( int i = IDB_PNG3 , k = NULL ; i < = IDB_PNG32 ; i + + , k + + )
2022-06-24 12:22:04 +02:00
{
2022-10-19 16:10:36 +02:00
m_vFlagIcons . push_back ( MODULERESOURCE ( GetModuleResource ( i ) ) ) ;
MODULERESOURCE & rFlagIcon = m_vFlagIcons [ k ] ;
2022-06-24 12:22:04 +02:00
2023-04-02 17:02:04 +02:00
ret = LoadTextureBuffer ( reinterpret_cast < unsigned char * > ( rFlagIcon . m_pData ) , // !TODO: Fall-back texture.
2022-10-19 16:10:36 +02:00
static_cast < int > ( rFlagIcon . m_nSize ) , & rFlagIcon . m_idIcon , & rFlagIcon . m_nWidth , & rFlagIcon . m_nHeight ) ;
IM_ASSERT ( ret ) ;
2023-04-16 00:41:48 +02:00
if ( ! ret )
{
break ;
}
2022-06-24 12:22:04 +02:00
}
2022-10-19 16:10:36 +02:00
return ret ;
2022-06-24 12:22:04 +02:00
}
2022-04-26 20:24:51 +02:00
//-----------------------------------------------------------------------------
2022-11-10 01:17:53 +01:00
// Purpose: returns flag texture index for CommandBase (must be aligned with resource.h!)
2022-11-10 21:19:17 +01:00
// in the future we should build the texture procedurally with use of popcnt.
2022-04-26 20:24:51 +02:00
// Input : nFlags -
//-----------------------------------------------------------------------------
2022-11-10 01:17:53 +01:00
int CConsole : : GetFlagTextureIndex ( int nFlags ) const
2022-04-26 20:24:51 +02:00
{
2022-11-10 01:17:53 +01:00
switch ( nFlags ) // All indices for single/dual flag textures.
2022-04-26 20:24:51 +02:00
{
case FCVAR_DEVELOPMENTONLY :
2022-11-11 20:12:20 +01:00
return 9 ;
2022-04-26 20:24:51 +02:00
case FCVAR_GAMEDLL :
2022-11-11 20:12:20 +01:00
return 10 ;
2022-04-26 20:24:51 +02:00
case FCVAR_CLIENTDLL :
2022-11-11 20:12:20 +01:00
return 11 ;
2022-10-11 01:22:21 +02:00
case FCVAR_REPLICATED :
2022-11-11 20:12:20 +01:00
return 12 ;
2022-10-11 01:22:21 +02:00
case FCVAR_CHEAT :
2022-11-11 20:12:20 +01:00
return 13 ;
2022-10-11 01:22:21 +02:00
case FCVAR_RELEASE :
2022-11-11 20:12:20 +01:00
return 14 ;
2022-10-11 01:22:21 +02:00
case FCVAR_MATERIAL_SYSTEM_THREAD :
2022-11-11 20:12:20 +01:00
return 15 ;
2022-10-11 01:22:21 +02:00
case FCVAR_DEVELOPMENTONLY | FCVAR_GAMEDLL :
2022-11-11 20:12:20 +01:00
return 16 ;
2022-10-11 01:22:21 +02:00
case FCVAR_DEVELOPMENTONLY | FCVAR_CLIENTDLL :
2022-11-11 20:12:20 +01:00
return 17 ;
2022-10-11 01:22:21 +02:00
case FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED :
2022-11-11 20:12:20 +01:00
return 18 ;
2022-10-11 01:22:21 +02:00
case FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT :
2022-11-11 20:12:20 +01:00
return 19 ;
2022-10-11 01:22:21 +02:00
case FCVAR_DEVELOPMENTONLY | FCVAR_MATERIAL_SYSTEM_THREAD :
2022-11-11 20:12:20 +01:00
return 20 ;
2022-10-11 01:22:21 +02:00
case FCVAR_REPLICATED | FCVAR_CHEAT :
2022-11-11 20:12:20 +01:00
return 21 ;
2022-10-11 01:22:21 +02:00
case FCVAR_REPLICATED | FCVAR_RELEASE :
2022-11-11 20:12:20 +01:00
return 22 ;
2022-10-11 01:22:21 +02:00
case FCVAR_GAMEDLL | FCVAR_CHEAT :
2022-11-11 20:12:20 +01:00
return 23 ;
2022-10-11 01:22:21 +02:00
case FCVAR_GAMEDLL | FCVAR_RELEASE :
2022-11-11 20:12:20 +01:00
return 24 ;
2022-10-11 01:22:21 +02:00
case FCVAR_CLIENTDLL | FCVAR_CHEAT :
2022-11-11 20:12:20 +01:00
return 25 ;
2022-10-11 01:22:21 +02:00
case FCVAR_CLIENTDLL | FCVAR_RELEASE :
2022-11-11 20:12:20 +01:00
return 26 ;
2022-10-11 01:22:21 +02:00
case FCVAR_MATERIAL_SYSTEM_THREAD | FCVAR_CHEAT :
2022-11-11 20:12:20 +01:00
return 27 ;
2022-10-11 01:22:21 +02:00
case FCVAR_MATERIAL_SYSTEM_THREAD | FCVAR_RELEASE :
2022-11-11 20:12:20 +01:00
return 28 ;
2023-02-05 19:21:39 +01:00
case COMMAND_COMPLETION_MARKER :
return 29 ;
2022-11-10 01:17:53 +01:00
2022-11-11 20:12:20 +01:00
default : // Hit when flag is zero/non-indexed or 3+ bits are set.
2022-11-10 01:17:53 +01:00
int v = __popcnt ( nFlags ) ;
switch ( v )
{
case 0 :
2022-11-10 21:19:17 +01:00
return 0 ; // Pink checker texture (FCVAR_NONE)
2022-11-10 01:17:53 +01:00
case 1 :
2022-11-10 21:19:17 +01:00
return 1 ; // Yellow checker texture (non-indexed).
2022-11-10 01:17:53 +01:00
default :
2022-11-10 21:19:17 +01:00
// If 3 or more bits are set, we test the flags
// and display the appropriate checker texture.
bool mul = v > 2 ;
2022-11-10 01:17:53 +01:00
if ( nFlags & FCVAR_DEVELOPMENTONLY )
{
2022-11-11 20:12:20 +01:00
return mul ? 4 : 3 ;
2022-11-10 01:17:53 +01:00
}
else if ( nFlags & FCVAR_CHEAT )
{
2022-11-11 20:12:20 +01:00
return mul ? 6 : 5 ;
}
else if ( nFlags & FCVAR_RELEASE & & // RELEASE command but no context restriction.
! ( nFlags & FCVAR_SERVER_CAN_EXECUTE ) & &
! ( nFlags & FCVAR_CLIENTCMD_CAN_EXECUTE ) )
{
return mul ? 8 : 7 ;
2022-11-10 01:17:53 +01:00
}
2022-11-10 21:19:17 +01:00
// Rainbow checker texture (user needs to manually check flags).
// These commands are not restricted if ran from the same context.
return 2 ;
2022-11-10 01:17:53 +01:00
}
2022-04-26 20:24:51 +02:00
}
}
2021-12-25 22:36:38 +01:00
//-----------------------------------------------------------------------------
2022-01-17 23:20:03 +01:00
// Purpose: console input box callback
2022-02-14 02:31:42 +01:00
// Input : *iData -
// Output :
2021-12-25 22:36:38 +01:00
//-----------------------------------------------------------------------------
2022-02-14 02:31:42 +01:00
int CConsole : : TextEditCallback ( ImGuiInputTextCallbackData * iData )
2021-12-25 22:36:38 +01:00
{
2022-02-14 02:31:42 +01:00
switch ( iData - > EventFlag )
2021-12-25 22:36:38 +01:00
{
case ImGuiInputTextFlags_CallbackCompletion :
{
// Locate beginning of current word.
2022-02-14 02:31:42 +01:00
const char * pszWordEnd = iData - > Buf + iData - > CursorPos ;
2022-01-14 20:45:36 +01:00
const char * pszWordStart = pszWordEnd ;
2022-02-14 02:31:42 +01:00
while ( pszWordStart > iData - > Buf )
2021-12-25 22:36:38 +01:00
{
2022-01-14 20:45:36 +01:00
const char c = pszWordStart [ - 1 ] ;
2021-12-25 22:36:38 +01:00
if ( c = = ' ' | | c = = ' \t ' | | c = = ' , ' | | c = = ' ; ' )
{
break ;
}
2022-01-14 20:45:36 +01:00
pszWordStart - - ;
2021-12-25 22:36:38 +01:00
}
break ;
}
case ImGuiInputTextFlags_CallbackHistory :
{
2022-01-17 23:20:03 +01:00
if ( m_bSuggestActive )
2021-12-25 22:36:38 +01:00
{
2022-02-14 02:31:42 +01:00
if ( iData - > EventKey = = ImGuiKey_UpArrow & & m_nSuggestPos > - 1 )
2021-12-25 22:36:38 +01:00
{
2022-01-17 23:20:03 +01:00
m_nSuggestPos - - ;
m_bSuggestMoved = true ;
}
2022-02-14 02:31:42 +01:00
else if ( iData - > EventKey = = ImGuiKey_DownArrow )
2022-01-17 23:20:03 +01:00
{
2022-06-24 12:22:04 +02:00
if ( m_nSuggestPos < static_cast < ssize_t > ( m_vSuggest . size ( ) ) - 1 )
2021-12-25 22:36:38 +01:00
{
2022-01-17 23:20:03 +01:00
m_nSuggestPos + + ;
m_bSuggestMoved = true ;
2021-12-25 22:36:38 +01:00
}
}
}
2022-11-10 21:19:17 +01:00
else // Allow user to navigate through the history if suggest panel isn't drawn.
2021-12-25 22:36:38 +01:00
{
2022-08-14 18:35:01 +02:00
const ssize_t nPrevHistoryPos = m_nHistoryPos ;
2022-02-14 02:31:42 +01:00
if ( iData - > EventKey = = ImGuiKey_UpArrow )
2022-01-17 23:20:03 +01:00
{
2023-09-17 11:38:00 +02:00
if ( m_nHistoryPos = = PositionMode_t : : kPark )
2022-01-17 23:20:03 +01:00
{
2022-06-24 12:22:04 +02:00
m_nHistoryPos = static_cast < ssize_t > ( m_vHistory . size ( ) ) - 1 ;
2022-01-17 23:20:03 +01:00
}
else if ( m_nHistoryPos > 0 )
{
m_nHistoryPos - - ;
}
}
2022-02-14 02:31:42 +01:00
else if ( iData - > EventKey = = ImGuiKey_DownArrow )
2022-01-17 23:20:03 +01:00
{
2023-09-17 11:38:00 +02:00
if ( m_nHistoryPos ! = PositionMode_t : : kPark )
2022-01-17 23:20:03 +01:00
{
2022-06-24 12:22:04 +02:00
if ( + + m_nHistoryPos > = static_cast < ssize_t > ( m_vHistory . size ( ) ) )
2022-01-17 23:20:03 +01:00
{
2023-09-17 11:38:00 +02:00
m_nHistoryPos = PositionMode_t : : kPark ;
2022-01-17 23:20:03 +01:00
}
}
}
if ( nPrevHistoryPos ! = m_nHistoryPos )
{
2022-06-22 03:24:46 +02:00
string svHistory = ( m_nHistoryPos > = 0 ) ? m_vHistory [ m_nHistoryPos ] : " " ;
2022-01-17 23:20:03 +01:00
if ( ! svHistory . empty ( ) )
{
2023-08-08 02:19:45 +02:00
if ( svHistory . find ( ' ' ) = = string : : npos )
2022-01-17 23:20:03 +01:00
{
// Append whitespace to previous entered command if absent or no parameters where passed.
svHistory . append ( " " ) ;
}
}
2022-02-14 02:31:42 +01:00
iData - > DeleteChars ( 0 , iData - > BufTextLen ) ;
iData - > InsertChars ( 0 , svHistory . c_str ( ) ) ;
2022-01-17 23:20:03 +01:00
}
2021-12-25 22:36:38 +01:00
}
2022-06-22 03:24:46 +02:00
BuildSummary ( iData - > Buf ) ;
2022-01-17 23:20:03 +01:00
break ;
2021-12-25 22:36:38 +01:00
}
2022-09-02 01:18:36 +02:00
case ImGuiInputTextFlags_CallbackAlways :
{
2022-11-10 22:01:34 +01:00
m_nInputTextLen = iData - > BufTextLen ;
2022-11-10 21:19:17 +01:00
if ( m_bModifyInput ) // User entered a value in the input field.
2022-09-02 01:18:36 +02:00
{
2022-11-10 22:01:34 +01:00
iData - > DeleteChars ( 0 , m_nInputTextLen ) ;
2022-09-07 01:55:52 +02:00
2022-11-10 21:19:17 +01:00
if ( ! m_svInputConVar . empty ( ) ) // User selected a ConVar from the suggestion window, copy it to the buffer.
2022-09-02 01:18:36 +02:00
{
iData - > InsertChars ( 0 , m_svInputConVar . c_str ( ) ) ;
m_svInputConVar . clear ( ) ;
2023-02-05 22:50:11 +01:00
2023-02-06 02:12:53 +01:00
m_bCanAutoComplete = true ;
2023-02-06 00:04:08 +01:00
m_bReclaimFocus = true ;
2022-09-02 01:18:36 +02:00
}
m_bModifyInput = false ;
}
break ;
}
2022-11-10 21:19:17 +01:00
case ImGuiInputTextFlags_CallbackCharFilter :
2022-01-28 12:56:51 +01:00
{
2022-11-10 21:19:17 +01:00
const ImWchar c = iData - > EventChar ;
2022-11-10 22:01:34 +01:00
if ( ! m_nInputTextLen )
2022-06-24 14:23:12 +02:00
{
2022-12-21 23:46:27 +01:00
if ( c = = ' ~ ' ) // Discard tilde character as first input.
2022-06-24 14:23:12 +02:00
{
2022-11-10 21:19:17 +01:00
iData - > EventChar = 0 ;
return 1 ;
2022-06-24 14:23:12 +02:00
}
2022-11-10 21:19:17 +01:00
}
if ( c = = ' ` ' ) // Discard back quote character (default console invoke key).
{
iData - > EventChar = 0 ;
return 1 ;
}
2022-09-05 01:33:40 +02:00
2022-11-10 21:19:17 +01:00
return 0 ;
}
case ImGuiInputTextFlags_CallbackEdit :
{
2022-11-10 22:03:27 +01:00
// If user selected all text in the input field and replaces it with
// a tilde or space character, it will be set as the first character
// in the input field as m_nInputTextLen is set before the actual edit.
while ( iData - > Buf [ 0 ] = = ' ~ ' | | iData - > Buf [ 0 ] = = ' ' )
{
iData - > DeleteChars ( 0 , 1 ) ;
}
2022-11-10 22:01:34 +01:00
if ( iData - > BufTextLen ) // Attempt to build a summary..
2022-11-10 21:19:17 +01:00
{
2022-09-05 01:33:40 +02:00
BuildSummary ( iData - > Buf ) ;
2023-02-06 02:12:53 +01:00
m_bCanAutoComplete = true ;
2022-09-05 01:33:40 +02:00
}
else // Reset state and enable history scrolling when buffer is empty.
{
2023-09-17 16:15:42 +02:00
ResetAutoComplete ( ) ;
2022-06-24 14:23:12 +02:00
}
2022-06-22 03:24:46 +02:00
break ;
2022-01-28 12:56:51 +01:00
}
2021-12-25 22:36:38 +01:00
}
2022-11-10 21:19:17 +01:00
return 0 ;
2021-12-25 22:36:38 +01:00
}
2022-01-12 02:53:07 +01:00
//-----------------------------------------------------------------------------
2022-01-17 23:20:03 +01:00
// Purpose: console input box callback stub
2022-02-14 02:31:42 +01:00
// Input : *iData -
// Output :
2022-01-12 02:53:07 +01:00
//-----------------------------------------------------------------------------
2022-02-14 02:31:42 +01:00
int CConsole : : TextEditCallbackStub ( ImGuiInputTextCallbackData * iData )
2022-01-12 02:53:07 +01:00
{
2022-02-23 15:56:03 +01:00
CConsole * pConsole = reinterpret_cast < CConsole * > ( iData - > UserData ) ;
2022-02-14 02:31:42 +01:00
return pConsole - > TextEditCallback ( iData ) ;
2022-01-12 02:53:07 +01:00
}
2022-06-20 10:31:09 +02:00
//-----------------------------------------------------------------------------
// Purpose: adds logs to the vector
// Input : &conLog -
//-----------------------------------------------------------------------------
2022-06-26 17:40:02 +02:00
void CConsole : : AddLog ( const ConLog_t & conLog )
2022-06-20 10:31:09 +02:00
{
2024-01-21 23:06:26 +01:00
AUTO_LOCK ( m_Mutex ) ;
2022-06-20 10:31:09 +02:00
m_Logger . InsertText ( conLog ) ;
}
2022-01-12 02:53:07 +01:00
//-----------------------------------------------------------------------------
2022-08-21 19:35:06 +02:00
// Purpose: adds logs to the vector (internal)
2022-10-19 16:10:36 +02:00
// Only call when mutex lock is obtained!
// Input : &color -
// *fmt -
2022-02-14 02:31:42 +01:00
// ... -
2022-01-12 02:53:07 +01:00
//-----------------------------------------------------------------------------
2023-04-01 21:42:34 +02:00
void CConsole : : AddLog ( const ImVec4 & color , const char * fmt , . . . ) /*IM_FMTARGS(2)*/
2022-01-12 02:53:07 +01:00
{
2023-04-01 21:42:34 +02:00
string result ;
va_list args ;
2022-01-12 02:53:07 +01:00
va_start ( args , fmt ) ;
2023-04-01 21:42:34 +02:00
result = FormatV ( fmt , args ) ;
2022-01-12 02:53:07 +01:00
va_end ( args ) ;
2023-04-01 21:42:34 +02:00
m_Logger . InsertText ( ConLog_t ( result , color ) ) ;
2022-01-12 02:53:07 +01:00
}
2021-12-25 22:36:38 +01:00
2022-10-18 02:11:52 +02:00
//-----------------------------------------------------------------------------
// Purpose: removes lines from console with sanitized start and end indices
// input : nStart -
// nEnd -
//-----------------------------------------------------------------------------
void CConsole : : RemoveLog ( int nStart , int nEnd )
{
2024-01-21 23:06:26 +01:00
AUTO_LOCK ( m_Mutex ) ;
const int nLines = m_Logger . GetTotalLines ( ) ;
2022-10-24 00:50:07 +02:00
2022-10-18 02:11:52 +02:00
if ( nEnd > = nLines )
{
// Sanitize for last array elem.
nEnd = ( nLines - 1 ) ;
}
if ( nStart > = nEnd )
{
if ( nEnd > 0 )
{
nStart = ( nEnd - 1 ) ;
}
else
{
// First elem cannot be removed!
return ;
}
}
else if ( nStart < 0 )
{
nStart = 0 ;
}
// User wants to remove everything.
if ( nLines < = ( nStart - nEnd ) )
{
ClearLog ( ) ;
return ;
}
m_Logger . RemoveLine ( nStart , nEnd ) ;
}
2022-01-12 02:53:07 +01:00
//-----------------------------------------------------------------------------
2022-06-20 10:31:09 +02:00
// Purpose: clears the entire log vector
2022-01-12 02:53:07 +01:00
//-----------------------------------------------------------------------------
2022-06-20 10:31:09 +02:00
void CConsole : : ClearLog ( void )
2021-12-25 22:36:38 +01:00
{
2024-01-21 23:06:26 +01:00
AUTO_LOCK ( m_Mutex ) ;
2022-06-24 12:22:04 +02:00
m_Logger . RemoveLine ( 0 , ( m_Logger . GetTotalLines ( ) - 1 ) ) ;
2022-01-12 02:53:07 +01:00
}
2022-10-19 16:10:36 +02:00
//-----------------------------------------------------------------------------
// Purpose: gets all console submissions
// Output : vector of strings
//-----------------------------------------------------------------------------
2022-10-24 00:50:07 +02:00
vector < string > CConsole : : GetHistory ( void ) const
2022-10-19 16:10:36 +02:00
{
2024-01-21 23:06:26 +01:00
AUTO_LOCK ( m_Mutex ) ;
2022-10-19 16:10:36 +02:00
return m_vHistory ;
}
//-----------------------------------------------------------------------------
// Purpose: clears the entire submission history vector
//-----------------------------------------------------------------------------
void CConsole : : ClearHistory ( void )
{
2024-01-21 23:06:26 +01:00
AUTO_LOCK ( m_Mutex ) ;
2022-10-19 16:10:36 +02:00
m_vHistory . clear ( ) ;
BuildSummary ( ) ;
}
2022-01-12 02:53:07 +01:00
//-----------------------------------------------------------------------------
// Purpose: sets the console front-end style
//-----------------------------------------------------------------------------
2022-01-17 23:20:03 +01:00
void CConsole : : SetStyleVar ( void )
2022-01-12 02:53:07 +01:00
{
2022-08-22 01:10:18 +02:00
m_Style = g_pImGuiConfig - > InitStyle ( ) ;
2022-06-24 12:22:04 +02:00
2022-06-24 12:45:47 +02:00
ImGui : : SetNextWindowSize ( ImVec2 ( 1200 , 524 ) , ImGuiCond_FirstUseEver ) ;
2022-06-24 12:22:04 +02:00
ImGui : : SetWindowPos ( ImVec2 ( - 1000 , 50 ) , ImGuiCond_FirstUseEver ) ;
2021-12-25 22:36:38 +01:00
}
2024-02-23 00:12:06 +01:00
//-----------------------------------------------------------------------------
// Purpose: toggles the console
//-----------------------------------------------------------------------------
void CConsole : : ToggleConsole_f ( )
{
g_Console . m_bActivate ^ = true ;
ResetInput ( ) ; // Disable input to game when console is drawn.
}
//-----------------------------------------------------------------------------
// Purpose: shows the game console submission history.
//-----------------------------------------------------------------------------
void CConsole : : LogHistory_f ( )
{
const vector < string > vHistory = g_Console . GetHistory ( ) ;
for ( size_t i = 0 , nh = vHistory . size ( ) ; i < nh ; i + + )
{
Msg ( eDLL_T : : COMMON , " %3d: %s \n " , i , vHistory [ i ] . c_str ( ) ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose: removes a range of lines from the console.
//-----------------------------------------------------------------------------
void CConsole : : RemoveLine_f ( const CCommand & args )
{
if ( args . ArgC ( ) < 3 )
{
Msg ( eDLL_T : : CLIENT , " Usage 'con_removeline': start(int) end(int) \n " ) ;
return ;
}
int start = atoi ( args [ 1 ] ) ;
int end = atoi ( args [ 2 ] ) ;
g_Console . RemoveLog ( start , end ) ;
}
//-----------------------------------------------------------------------------
// Purpose: clears all lines from the developer console.
//-----------------------------------------------------------------------------
void CConsole : : ClearLines_f ( )
{
g_Console . ClearLog ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: clears all submissions from the developer console history.
//-----------------------------------------------------------------------------
void CConsole : : ClearHistory_f ( )
{
g_Console . ClearHistory ( ) ;
}
2024-01-21 21:29:23 +01:00
CConsole g_Console ;