source-engine/game/client/vgui_messagechars.cpp
2022-03-01 23:00:42 +03:00

468 lines
11 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include <stdarg.h>
#include "imessagechars.h"
#include <vgui/IVGui.h>
#include "VGuiMatSurface/IMatSystemSurface.h"
#include <vgui_controls/Panel.h>
#include <vgui_controls/Controls.h>
#include <vgui/IScheme.h>
#include <vgui/ISurface.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// Simultaneous message limit
#define MAX_MESSAGECHARS_MESSAGES 1024
#define MAX_MESSAGECHARSPANEL_LEN 1024
//-----------------------------------------------------------------------------
// Purpose: Panel for displaying console characters at specified locations
//-----------------------------------------------------------------------------
class CMessageCharsPanel : public vgui::Panel
{
typedef vgui::Panel BaseClass;
public:
// Internal pool of such messages
typedef struct message_s
{
struct message_s *next;
int x, y;
byte r, g, b, a;
char *text;
vgui::HFont hCustomFont;
float fTTL;
int messageID;
} message_t;
// Construct/destruct
CMessageCharsPanel( vgui::VPANEL parent );
virtual ~CMessageCharsPanel( void );
// Add block of text to list
virtual int AddText(
float flTime,
vgui::HFont hCustomFont,
int x,
int y,
int r,
int g,
int b,
int a,
char *fmt,
int messageID,
... );
// Determine text side and height
virtual void GetTextExtents( vgui::HFont hCustomFont, int *wide, int *tall, const char *string );
virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
virtual void Paint();
virtual void OnTick( void );
virtual bool ShouldDraw( void );
void RemoveStringsByID( int messageID );
void Clear( void );
private:
// Allocate a new message
message_t *AllocMessage( void );
// Clear out all messages
void Reset( void );
vgui::HFont m_hFont;
// Pool of messages
message_t m_Messages[ MAX_MESSAGECHARS_MESSAGES ];
message_t *m_pActive;
message_t *m_pFree;
};
//-----------------------------------------------------------------------------
// Purpose:
// Input : *parent -
// Output :
//-----------------------------------------------------------------------------
CMessageCharsPanel::CMessageCharsPanel( vgui::VPANEL parent ) :
BaseClass( NULL, "CMessageCharsPanel" )
{
SetParent( parent );
SetSize( ScreenWidth(), ScreenHeight() );
SetPos( 0, 0 );
SetVisible( true );
SetCursor( null );
SetKeyBoardInputEnabled( false );
SetMouseInputEnabled( false );
m_hFont = vgui::INVALID_FONT;
SetFgColor( Color( 0, 0, 0, 255 ) );
SetPaintBackgroundEnabled( false );
Q_memset( m_Messages, 0, sizeof( m_Messages ) );
Reset();
vgui::ivgui()->AddTickSignal( GetVPanel(), 100 );
}
//-----------------------------------------------------------------------------
// Purpose:
// Output :
//-----------------------------------------------------------------------------
CMessageCharsPanel::~CMessageCharsPanel( void )
{
}
void CMessageCharsPanel::ApplySchemeSettings(vgui::IScheme *pScheme)
{
BaseClass::ApplySchemeSettings(pScheme);
m_hFont = pScheme->GetFont( "Default" );
Assert( m_hFont != vgui::INVALID_FONT );
SetSize( ScreenWidth(), ScreenHeight() );
SetPos( 0, 0 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMessageCharsPanel::Clear( void )
{
Reset();
}
//-----------------------------------------------------------------------------
// Purpose: Reset all messages
//-----------------------------------------------------------------------------
void CMessageCharsPanel::Reset( void )
{
m_pActive = NULL;
int i;
for( i = 0; i < MAX_MESSAGECHARS_MESSAGES-1; i++ )
{
if ( m_Messages[ i ].text )
{
delete[] m_Messages[ i ].text;
m_Messages[ i ].text = NULL;
}
m_Messages[ i ].next = &m_Messages[ i + 1 ];
}
m_Messages[ i ].next = NULL;
m_pFree = &m_Messages[ 0 ];
SetVisible( false );
}
//-----------------------------------------------------------------------------
// Purpose: Allocate a message if possible
// Output : CMessageCharsPanel::message_t
//-----------------------------------------------------------------------------
CMessageCharsPanel::message_t *CMessageCharsPanel::AllocMessage( void )
{
CMessageCharsPanel::message_t *msg;
if ( !m_pFree )
return NULL;
msg = m_pFree;
m_pFree = m_pFree->next;
msg->next = m_pActive;
m_pActive = msg;
msg->x = 0;
msg->y = 0;
msg->text = NULL;
msg->hCustomFont = NULL;
return msg;
}
//-----------------------------------------------------------------------------
// Purpose: Allocate message and fill in data
// Input : x -
// y -
// *fmt -
// ... -
// Output : int
//-----------------------------------------------------------------------------
int CMessageCharsPanel::AddText(
float flTime,
vgui::HFont hCustomFont,
int x,
int y,
int r,
int g,
int b,
int a,
char *fmt,
int messageID,
... )
{
va_list argptr;
char data[ MAX_MESSAGECHARSPANEL_LEN ];
int len;
va_start(argptr, messageID);
len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
va_end(argptr);
data[ MAX_MESSAGECHARSPANEL_LEN - 1 ] = 0;
CMessageCharsPanel::message_t *msg = AllocMessage();
if ( !msg )
return x;
msg->x = x;
msg->y = y;
msg->r = r;
msg->g = g;
msg->b = b;
msg->a = a;
msg->messageID = messageID;
Assert( !msg->text );
int textLength = Q_strlen( data ) + 1;
msg->text = new char[ textLength ];
Assert( msg->text );
Q_strncpy( msg->text, data, textLength );
if ( flTime )
msg->fTTL = gpGlobals->curtime + flTime;
else
msg->fTTL = 0;
SetVisible( true );
if ( hCustomFont )
msg->hCustomFont = hCustomFont;
else
msg->hCustomFont = m_hFont;
// Return new cursor position
return x + g_pMatSystemSurface->DrawTextLen( msg->hCustomFont, data );
}
//-----------------------------------------------------------------------------
// Purpose: Determine text size ahead of time
// Input : *wide -
// *tall -
// *string -
//-----------------------------------------------------------------------------
void CMessageCharsPanel::GetTextExtents( vgui::HFont hCustomFont, int *wide, int *tall, const char *string )
{
if ( !hCustomFont )
{
// Make sure we actually have the font...
vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
hCustomFont = pScheme->GetFont( "Default" );
}
Assert( hCustomFont );
*wide = g_pMatSystemSurface->DrawTextLen( hCustomFont, (char *)string );
*tall = vgui::surface()->GetFontTall( hCustomFont );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMessageCharsPanel::OnTick( void )
{
bool bVisible = ShouldDraw();
if ( IsVisible() != bVisible )
{
SetVisible( bVisible );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CMessageCharsPanel::ShouldDraw( void )
{
if ( !m_pActive )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
//-----------------------------------------------------------------------------
void CMessageCharsPanel::Paint()
{
CMessageCharsPanel::message_t *msg = m_pActive;
while ( msg )
{
g_pMatSystemSurface->DrawColoredText( msg->hCustomFont, msg->x, msg->y, msg->r, msg->g, msg->b, msg->a, msg->text );
msg = msg->next;
}
// Clear our dead messages
message_t *pPrev = NULL;
message_t *pCurrent = m_pActive;
while ( pCurrent )
{
if ( pCurrent->fTTL <= gpGlobals->curtime )
{
// Move it to the free list
if ( !pPrev )
{
m_pActive = pCurrent->next;
}
else
{
pPrev->next = pCurrent->next;
}
// Store off next one, because we're about to move the current
message_t *pNext = pCurrent->next;
delete[] pCurrent->text;
pCurrent->text = NULL;
pCurrent->next = m_pFree;
m_pFree = pCurrent;
// Don't advance pPrev
pCurrent = pNext;
continue;
}
pPrev = pCurrent;
pCurrent = pCurrent->next;
}
}
void CMessageCharsPanel::RemoveStringsByID( int messageID )
{
for ( message_t *pCurrent = m_pActive; pCurrent; pCurrent = pCurrent->next )
{
if ( pCurrent->messageID == messageID )
pCurrent->fTTL = gpGlobals->curtime - 1000;
}
}
class CMessageChars : public IMessageChars
{
private:
CMessageCharsPanel *messageCharsPanel;
public:
CMessageChars( void )
{
messageCharsPanel = NULL;
}
void Create( vgui::VPANEL parent )
{
messageCharsPanel = new CMessageCharsPanel( parent );
}
void Destroy( void )
{
if ( messageCharsPanel )
{
messageCharsPanel->SetParent( (vgui::Panel *)NULL );
delete messageCharsPanel;
messageCharsPanel = NULL;
}
}
int DrawStringForTime( float flTime, vgui::HFont hCustomFont, int x, int y, int r, int g, int b, int a, const char *fmt, int messageID, ... )
{
va_list argptr;
char data[ MAX_MESSAGECHARSPANEL_LEN ];
int len;
va_start(argptr, messageID);
len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
va_end(argptr);
data[ MAX_MESSAGECHARSPANEL_LEN - 1 ] = 0;
if ( !messageCharsPanel )
return x;
return messageCharsPanel->AddText( flTime, hCustomFont, x, y, r, g, b, a, data, messageID );
}
int DrawStringForTime( float flTime, vgui::HFont hCustomFont, int x, int y, const char *fmt, int messageID, ... )
{
int r = 192, g = 192, b = 192;
va_list argptr;
va_start(argptr, messageID);
int result = DrawString( hCustomFont, x, y, r, g, b, 255, fmt, messageID, argptr );
va_end( argptr );
return result;
}
virtual void RemoveStringsByID( int messageID )
{
messageCharsPanel->RemoveStringsByID( messageID );
}
int DrawString( vgui::HFont hCustomFont, int x, int y, int r, int g, int b, int a, const char *fmt, int messageID, ... )
{
va_list argptr;
va_start(argptr, messageID);
int result = DrawStringForTime( 0, hCustomFont, x, y, r, g, b, a, fmt, messageID, argptr );
va_end( argptr );
return result;
}
int DrawString( vgui::HFont hCustomFont, int x, int y, const char *fmt, int messageID, ... )
{
va_list argptr;
va_start(argptr, messageID);
int result = DrawStringForTime( 0, hCustomFont, x, y, fmt, messageID, argptr );
va_end( argptr );
return result;
}
void GetStringLength( vgui::HFont hCustomFont, int *width, int *height, const char *fmt, ... )
{
if ( !messageCharsPanel )
{
return;
}
va_list argptr;
char data[ MAX_MESSAGECHARSPANEL_LEN ];
int len;
va_start(argptr, fmt);
len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
va_end(argptr);
data[ MAX_MESSAGECHARSPANEL_LEN - 1 ] = 0;
messageCharsPanel->GetTextExtents( hCustomFont, width, height, data );
}
void Clear( void )
{
if ( !messageCharsPanel )
return;
messageCharsPanel->Clear();
}
};
static CMessageChars g_MessageChars;
IMessageChars *messagechars = ( IMessageChars * )&g_MessageChars;