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.
1437 lines
37 KiB
1437 lines
37 KiB
![]()
4 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
// $NoKeywords: $
|
||
|
//=============================================================================
|
||
|
#include "cbase.h"
|
||
|
|
||
|
#include "econ_notifications.h"
|
||
|
|
||
|
#include "hudelement.h"
|
||
|
#include "iclientmode.h"
|
||
|
#include "ienginevgui.h"
|
||
|
#include "vgui_avatarimage.h"
|
||
|
#include "vgui_controls/Controls.h"
|
||
|
#include "vgui_controls/EditablePanel.h"
|
||
|
#include "vgui_controls/TextImage.h"
|
||
|
#include "vgui/ILocalize.h"
|
||
|
#include "vgui/ISurface.h"
|
||
|
#include "vgui/IVGui.h"
|
||
|
#include "rtime.h"
|
||
|
#include "econ_controls.h"
|
||
|
#include "hud_basechat.h"
|
||
|
#include "hud_vote.h"
|
||
|
#include "inputsystem/iinputsystem.h"
|
||
|
#include "iinput.h"
|
||
|
|
||
|
// memdbgon must be the last include file in a .cpp file!!!
|
||
|
#include <tier0/memdbgon.h>
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
ConVar cl_notifications_show_ingame( "cl_notifications_show_ingame", "1", FCVAR_ARCHIVE, "Whether notifications should show up in-game." );
|
||
|
ConVar cl_notifications_max_num_visible( "cl_notifications_max_num_visible", "3", FCVAR_ARCHIVE, "How many notifications are visible in-game." );
|
||
|
ConVar cl_notifications_move_time( "cl_notifications_move_time", "0.5", FCVAR_ARCHIVE, "How long it takes for a notification to move." );
|
||
|
|
||
|
// notification queue holds all the notifications
|
||
|
class CEconNotificationQueue
|
||
|
{
|
||
|
public:
|
||
|
CEconNotificationQueue();
|
||
|
~CEconNotificationQueue();
|
||
|
|
||
|
int AddNotification( CEconNotification *pNotification );
|
||
|
void RemoveAllNotifications();
|
||
|
void RemoveNotification( int iID );
|
||
|
void RemoveNotification( CEconNotification *pNotification );
|
||
|
void RemoveNotifications( NotificationFilterFunc func );
|
||
|
int CountNotifications( NotificationFilterFunc func );
|
||
|
void VisitNotifications( CEconNotificationVisitor &visitor );
|
||
|
CEconNotification *GetNotification( int iID );
|
||
|
CEconNotification *GetNotificationByIndex( int idx );
|
||
|
void Update();
|
||
|
bool HasItems() { return m_vecNotifications.Count() != 0; }
|
||
|
const CUtlVector< CEconNotification *> &GetItems() { return m_vecNotifications; }
|
||
|
|
||
|
private:
|
||
|
int m_iIDGenerator;
|
||
|
CUtlVector< CEconNotification *> m_vecNotifications;
|
||
|
};
|
||
|
static CEconNotificationQueue g_notificationQueue;
|
||
|
|
||
|
CEconNotificationQueue::CEconNotificationQueue()
|
||
|
: m_iIDGenerator(0)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
CEconNotificationQueue::~CEconNotificationQueue()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
int CEconNotificationQueue::AddNotification( CEconNotification *pNotification )
|
||
|
{
|
||
|
int iID = ++m_iIDGenerator;
|
||
|
pNotification->m_iID = iID;
|
||
|
m_vecNotifications.AddToTail( pNotification );
|
||
|
return iID;
|
||
|
}
|
||
|
|
||
|
void CEconNotificationQueue::RemoveAllNotifications()
|
||
|
{
|
||
|
m_vecNotifications.PurgeAndDeleteElements();
|
||
|
}
|
||
|
|
||
|
void CEconNotificationQueue::RemoveNotification( int iID )
|
||
|
{
|
||
|
FOR_EACH_VEC( m_vecNotifications, i )
|
||
|
{
|
||
|
CEconNotification *pNotification = m_vecNotifications[i];
|
||
|
if ( pNotification->GetID() == iID )
|
||
|
{
|
||
|
delete pNotification;
|
||
|
m_vecNotifications.Remove( i );
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CEconNotificationQueue::RemoveNotification( CEconNotification *pNotification )
|
||
|
{
|
||
|
if ( pNotification )
|
||
|
{
|
||
|
RemoveNotification( pNotification->GetID() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CEconNotificationQueue::RemoveNotifications( NotificationFilterFunc func )
|
||
|
{
|
||
|
for ( int i = 0; i < m_vecNotifications.Count(); ++i)
|
||
|
{
|
||
|
CEconNotification *pNotification = m_vecNotifications[i];
|
||
|
if ( func( pNotification ) )
|
||
|
{
|
||
|
pNotification->MarkForDeletion();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int CEconNotificationQueue::CountNotifications( NotificationFilterFunc func )
|
||
|
{
|
||
|
int nResult = 0;
|
||
|
for ( int i = 0; i < m_vecNotifications.Count(); ++i)
|
||
|
{
|
||
|
CEconNotification *pNotification = m_vecNotifications[i];
|
||
|
if ( func( pNotification ) )
|
||
|
{
|
||
|
++nResult;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
void CEconNotificationQueue::VisitNotifications( CEconNotificationVisitor &visitor )
|
||
|
{
|
||
|
for ( int i = 0; i < m_vecNotifications.Count(); ++i )
|
||
|
{
|
||
|
CEconNotification *pNotification = m_vecNotifications[i];
|
||
|
visitor.Visit( *pNotification );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CEconNotification *CEconNotificationQueue::GetNotification( int iID )
|
||
|
{
|
||
|
FOR_EACH_VEC( m_vecNotifications, i )
|
||
|
{
|
||
|
CEconNotification *pNotification = m_vecNotifications[i];
|
||
|
if ( pNotification->GetID() == iID )
|
||
|
{
|
||
|
return pNotification;
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
CEconNotification *CEconNotificationQueue::GetNotificationByIndex( int idx )
|
||
|
{
|
||
|
if ( idx < 0 || idx >= m_vecNotifications.Count() )
|
||
|
{
|
||
|
Assert( !"Invalid index passed to GetNotificationByIndex" );
|
||
|
return NULL;
|
||
|
}
|
||
|
return m_vecNotifications[idx];
|
||
|
}
|
||
|
|
||
|
void CEconNotificationQueue::Update()
|
||
|
{
|
||
|
float flNowTime = engine->Time();
|
||
|
for ( int i = 0; i < m_vecNotifications.Count(); )
|
||
|
{
|
||
|
CEconNotification *pNotification = m_vecNotifications[i];
|
||
|
if ( pNotification->GetIsInUse() == false && pNotification->GetExpireTime() >= 0 && pNotification->GetExpireTime() < flNowTime )
|
||
|
{
|
||
|
pNotification->Expired();
|
||
|
delete pNotification;
|
||
|
m_vecNotifications.Remove( i );
|
||
|
continue;
|
||
|
}
|
||
|
pNotification->UpdateTick();
|
||
|
++i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
static void ColorizeText( CEconNotification *pNotification, CExLabel *pControl, const wchar_t* wszText )
|
||
|
{
|
||
|
static wchar_t wszStrippedText[2048];
|
||
|
|
||
|
if ( pControl == NULL )
|
||
|
return;
|
||
|
|
||
|
pControl->GetTextImage()->ClearColorChangeStream();
|
||
|
|
||
|
if ( wszText == NULL )
|
||
|
{
|
||
|
pControl->SetText( L"" );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Color newColor = pControl->GetFgColor();
|
||
|
int endIdx = 0;
|
||
|
int insertIdx = 0;
|
||
|
bool bContinue = true;
|
||
|
while ( bContinue )
|
||
|
{
|
||
|
bool bSetColor = false;
|
||
|
switch ( wszText[endIdx] )
|
||
|
{
|
||
|
case 0:
|
||
|
bContinue = false;
|
||
|
break;
|
||
|
case COLOR_NORMAL:
|
||
|
case COLOR_USEOLDCOLORS:
|
||
|
newColor = pControl->GetFgColor();
|
||
|
bSetColor = true;
|
||
|
break;
|
||
|
case COLOR_PLAYERNAME:
|
||
|
newColor = g_ColorYellow;
|
||
|
bSetColor = true;
|
||
|
break;
|
||
|
case COLOR_LOCATION:
|
||
|
newColor = g_ColorDarkGreen;
|
||
|
bSetColor = true;
|
||
|
break;
|
||
|
case COLOR_ACHIEVEMENT:
|
||
|
{
|
||
|
vgui::IScheme *pSourceScheme = vgui::scheme()->GetIScheme( vgui::scheme()->GetScheme( "SourceScheme" ) );
|
||
|
if ( pSourceScheme )
|
||
|
{
|
||
|
newColor = pSourceScheme->GetColor( "SteamLightGreen", pControl->GetBgColor() );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
newColor = pControl->GetFgColor();
|
||
|
}
|
||
|
bSetColor = true;
|
||
|
}
|
||
|
break;
|
||
|
case COLOR_CUSTOM:
|
||
|
newColor = pControl->GetFgColor();
|
||
|
KeyValues *pKeyValues = pNotification->GetKeyValues();
|
||
|
if ( pKeyValues )
|
||
|
{
|
||
|
KeyValues* pColor = pKeyValues->FindKey( "custom_color" );
|
||
|
if ( pColor )
|
||
|
{
|
||
|
newColor = pColor->GetColor();
|
||
|
}
|
||
|
}
|
||
|
bSetColor = true;
|
||
|
break;
|
||
|
}
|
||
|
if ( bSetColor )
|
||
|
{
|
||
|
pControl->GetTextImage()->AddColorChange( newColor, insertIdx );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wszStrippedText[insertIdx++] = wszText[endIdx];
|
||
|
}
|
||
|
++endIdx;
|
||
|
}
|
||
|
pControl->SetText( wszStrippedText );
|
||
|
}
|
||
|
|
||
|
// generic "toast" for notifications
|
||
|
class CGenericNotificationToast : public vgui::EditablePanel
|
||
|
{
|
||
|
DECLARE_CLASS_SIMPLE( CGenericNotificationToast, vgui::EditablePanel );
|
||
|
public:
|
||
|
CGenericNotificationToast( vgui::Panel *parent, int iNotificationID, bool bMainMenu );
|
||
|
virtual ~CGenericNotificationToast();
|
||
|
|
||
|
virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
|
||
|
virtual void PerformLayout();
|
||
|
protected:
|
||
|
int m_iNotificationID;
|
||
|
vgui::Panel *m_pAvatarBG;
|
||
|
CAvatarImagePanel *m_pAvatar;
|
||
|
bool m_bMainMenu;
|
||
|
};
|
||
|
|
||
|
CGenericNotificationToast::CGenericNotificationToast( vgui::Panel *parent, int iNotificationID, bool bMainMenu )
|
||
|
: BaseClass( parent, "GenericNotificationToast" )
|
||
|
, m_iNotificationID( iNotificationID )
|
||
|
, m_pAvatar( NULL )
|
||
|
, m_pAvatarBG( NULL )
|
||
|
, m_bMainMenu( bMainMenu )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
CGenericNotificationToast::~CGenericNotificationToast()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void CGenericNotificationToast::ApplySchemeSettings( vgui::IScheme *pScheme )
|
||
|
{
|
||
|
BaseClass::ApplySchemeSettings( pScheme );
|
||
|
|
||
|
CEconNotification *pNotification = NotificationQueue_Get( m_iNotificationID );
|
||
|
bool bHighPriority = pNotification && pNotification->BHighPriority();
|
||
|
KeyValues *pConditions = NULL;
|
||
|
|
||
|
if ( bHighPriority )
|
||
|
{
|
||
|
pConditions = new KeyValues( "conditions" );
|
||
|
if ( bHighPriority )
|
||
|
{
|
||
|
KeyValues *pSubKey = new KeyValues( "if_high_priority" );
|
||
|
pConditions->AddSubKey( pSubKey );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( m_bMainMenu )
|
||
|
{
|
||
|
LoadControlSettings( "Resource/UI/Econ/GenericNotificationToastMainMenu.res", NULL, NULL, pConditions );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LoadControlSettings( "Resource/UI/Econ/GenericNotificationToast.res", NULL, NULL, pConditions );
|
||
|
}
|
||
|
|
||
|
if ( pConditions )
|
||
|
{
|
||
|
pConditions->deleteThis();
|
||
|
}
|
||
|
|
||
|
m_pAvatar = dynamic_cast< CAvatarImagePanel *>( FindChildByName("AvatarImage") );
|
||
|
m_pAvatarBG = FindChildByName("AvatarBGPanel");
|
||
|
|
||
|
if ( pNotification )
|
||
|
{
|
||
|
if ( pNotification->GetSteamID() == CSteamID() )
|
||
|
{
|
||
|
ColorizeText( pNotification, dynamic_cast< CExLabel* >( FindChildByName( "TextLabel" ) ), pNotification->GetText() );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ColorizeText( pNotification, dynamic_cast< CExLabel* >( FindChildByName( "AvatarTextLabel" ) ), pNotification->GetText() );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CGenericNotificationToast::PerformLayout()
|
||
|
{
|
||
|
BaseClass::PerformLayout();
|
||
|
|
||
|
CSteamID steamID;
|
||
|
CEconNotification *pNotification = NotificationQueue_Get( m_iNotificationID );
|
||
|
if ( pNotification )
|
||
|
{
|
||
|
steamID = pNotification->GetSteamID();
|
||
|
}
|
||
|
|
||
|
int iMinHeight = 0;
|
||
|
if ( m_pAvatar )
|
||
|
{
|
||
|
if ( steamID != CSteamID() )
|
||
|
{
|
||
|
m_pAvatar->SetVisible( true );
|
||
|
m_pAvatar->SetShouldDrawFriendIcon( false );
|
||
|
m_pAvatar->SetPlayer( steamID, k_EAvatarSize64x64 );
|
||
|
// make sure there's a minimum height
|
||
|
// note we use iY to ensure that there's a buffer below too
|
||
|
int iX, iY, iWidth, iHeight;
|
||
|
m_pAvatar->GetBounds( iX, iY, iWidth, iHeight );
|
||
|
iMinHeight = 2 * iY + iHeight;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_pAvatar->SetVisible( false );
|
||
|
m_pAvatar->ClearAvatar();
|
||
|
}
|
||
|
}
|
||
|
if ( m_pAvatarBG )
|
||
|
{
|
||
|
m_pAvatarBG->SetVisible( m_pAvatar != NULL && m_pAvatar->IsVisible() );
|
||
|
}
|
||
|
|
||
|
const char *pTextLabelName = steamID != CSteamID() ? "AvatarTextLabel" : "TextLabel";
|
||
|
CExLabel* pText = dynamic_cast< CExLabel *>( FindChildByName( pTextLabelName ) );
|
||
|
if ( pText )
|
||
|
{
|
||
|
pText->SetVisible( true );
|
||
|
pText->InvalidateLayout( true, false );
|
||
|
int iWidth, iHeight;
|
||
|
pText->GetSize( iWidth, iHeight );
|
||
|
int iContentWidth, iContentHeight;
|
||
|
pText->GetContentSize( iContentWidth, iContentHeight );
|
||
|
pText->SetSize( iWidth, iContentHeight );
|
||
|
int iDelta = iContentHeight - iHeight;
|
||
|
// resize ourselves to fit
|
||
|
int iContainerWidth, iContainerHeight;
|
||
|
GetSize( iContainerWidth, iContainerHeight );
|
||
|
SetSize( iContainerWidth, MAX( iContainerHeight + iDelta, iMinHeight ) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
class CNotificationToastControl : public vgui::EditablePanel
|
||
|
{
|
||
|
DECLARE_CLASS_SIMPLE( CNotificationToastControl, vgui::EditablePanel );
|
||
|
public:
|
||
|
CNotificationToastControl( vgui::EditablePanel *pParent, vgui::EditablePanel *pNotificationToast, int iNotificationID, bool bAddControls )
|
||
|
: BaseClass( pParent, bAddControls ? "NotificationToastControl" : "NotificationToastContainer" )
|
||
|
, m_pChild( pNotificationToast )
|
||
|
, m_iNotificationID( iNotificationID )
|
||
|
, m_bAddControls( bAddControls )
|
||
|
, m_pTriggerButton( NULL )
|
||
|
, m_pAcceptButton( NULL )
|
||
|
, m_pDeclineButton( NULL )
|
||
|
, m_iOverrideHeight( 0 )
|
||
|
{
|
||
|
m_pChild->SetParent( this );
|
||
|
}
|
||
|
|
||
|
virtual ~CNotificationToastControl()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
virtual void ApplySchemeSettings( vgui::IScheme *scheme )
|
||
|
{
|
||
|
CEconNotification *pNotification = g_notificationQueue.GetNotification( m_iNotificationID );
|
||
|
|
||
|
// It is not entirely clear why pNotification is allowed to be NULL. Weapon switching
|
||
|
// with pyro was causing crashes because of pNotification being NULL, and there were
|
||
|
// previously existing checks, but it's not clear why.
|
||
|
CEconNotification::EType eNotificationType = pNotification ? pNotification->NotificationType() \
|
||
|
: CEconNotification::eType_Basic;
|
||
|
|
||
|
bool bHighPriority = pNotification && pNotification->BHighPriority();
|
||
|
bool bCanDelete = false;
|
||
|
bool bCanAcceptDecline = false;
|
||
|
bool bCanTrigger = false;
|
||
|
bool bOneButton = false;
|
||
|
|
||
|
switch ( eNotificationType )
|
||
|
{
|
||
|
case CEconNotification::eType_AcceptDecline:
|
||
|
bCanAcceptDecline = true;
|
||
|
break;
|
||
|
case CEconNotification::eType_Basic:
|
||
|
bCanDelete = true;
|
||
|
bOneButton = true;
|
||
|
break;
|
||
|
case CEconNotification::eType_MustTrigger:
|
||
|
bCanTrigger = true;
|
||
|
bOneButton = true;
|
||
|
break;
|
||
|
case CEconNotification::eType_Trigger:
|
||
|
bCanTrigger = true;
|
||
|
bCanDelete = true;
|
||
|
break;
|
||
|
default:
|
||
|
Assert( !"Unhandled enum type" );
|
||
|
}
|
||
|
|
||
|
KeyValues *pConditions = NULL;
|
||
|
|
||
|
if ( bOneButton || bHighPriority )
|
||
|
{
|
||
|
pConditions = new KeyValues( "conditions" );
|
||
|
if ( bOneButton )
|
||
|
{
|
||
|
KeyValues *pSubKey = new KeyValues( "if_one_button" );
|
||
|
pConditions->AddSubKey( pSubKey );
|
||
|
}
|
||
|
if ( bHighPriority )
|
||
|
{
|
||
|
KeyValues *pSubKey = new KeyValues( "if_high_priority" );
|
||
|
pConditions->AddSubKey( pSubKey );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( m_bAddControls )
|
||
|
{
|
||
|
LoadControlSettings( "Resource/UI/Econ/NotificationToastControl.res", NULL, NULL, pConditions );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LoadControlSettings( "Resource/UI/Econ/NotificationToastContainer.res", NULL, NULL, pConditions );
|
||
|
}
|
||
|
|
||
|
if ( pConditions )
|
||
|
{
|
||
|
pConditions->deleteThis();
|
||
|
}
|
||
|
|
||
|
BaseClass::ApplySchemeSettings( scheme );
|
||
|
|
||
|
GetSize( m_iOriginalWidth, m_iOriginalHeight );
|
||
|
|
||
|
CExButton *pDeleteButton = dynamic_cast< CExButton *>( FindChildByName( "DeleteButton" ) );
|
||
|
|
||
|
if ( pDeleteButton && bCanDelete )
|
||
|
{
|
||
|
pDeleteButton->AddActionSignalTarget( this );
|
||
|
pDeleteButton->SetVisible ( pNotification != NULL );
|
||
|
}
|
||
|
|
||
|
if ( pNotification == NULL )
|
||
|
return;
|
||
|
|
||
|
if ( bCanAcceptDecline )
|
||
|
{
|
||
|
m_pAcceptButton = dynamic_cast< CExButton * >( FindChildByName( "AcceptButton" ) );
|
||
|
m_pDeclineButton = dynamic_cast< CExButton * >( FindChildByName( "DeclineButton" ) );
|
||
|
if ( m_pAcceptButton && m_pDeclineButton )
|
||
|
{
|
||
|
m_pAcceptButton->AddActionSignalTarget( this );
|
||
|
m_pDeclineButton->AddActionSignalTarget( this );
|
||
|
m_pAcceptButton->SetVisible( true );
|
||
|
m_pDeclineButton->SetVisible( true );
|
||
|
int posX, posY;
|
||
|
m_pAcceptButton->GetPos( posX, posY );
|
||
|
m_iButtonOffsetY = GetTall() - posY;
|
||
|
}
|
||
|
}
|
||
|
if ( bCanTrigger )
|
||
|
{
|
||
|
m_pTriggerButton = dynamic_cast< CExButton *>( FindChildByName( "TriggerButton" ) );
|
||
|
if ( m_pTriggerButton )
|
||
|
{
|
||
|
m_pTriggerButton->AddActionSignalTarget( this );
|
||
|
m_pTriggerButton->SetVisible( true );
|
||
|
int posX, posY;
|
||
|
m_pTriggerButton->GetPos( posX, posY );
|
||
|
m_iButtonOffsetY = GetTall() - posY;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
virtual void PerformLayout()
|
||
|
{
|
||
|
BaseClass::PerformLayout();
|
||
|
m_pChild->PerformLayout();
|
||
|
int iWidth, iHeight;
|
||
|
m_pChild->GetSize( iWidth, iHeight );
|
||
|
|
||
|
// position control buttons
|
||
|
if ( iHeight + m_iButtonOffsetY > m_iOriginalHeight )
|
||
|
{
|
||
|
if ( m_pAcceptButton && m_pDeclineButton )
|
||
|
{
|
||
|
int posX, posY;
|
||
|
m_pAcceptButton->GetPos( posX, posY );
|
||
|
// int newPosY = iHeight;
|
||
|
// iHeight += m_iButtonOffsetY;
|
||
|
// m_pAcceptButton->SetPos( posX, newPosY );
|
||
|
// m_pDeclineButton->GetPos( posX, posY );
|
||
|
// m_pDeclineButton->SetPos( posX, newPosY );
|
||
|
}
|
||
|
else if ( m_pTriggerButton )
|
||
|
{
|
||
|
int posX, posY;
|
||
|
m_pTriggerButton->GetPos( posX, posY );
|
||
|
// posY = iHeight;
|
||
|
// iHeight += m_iButtonOffsetY;
|
||
|
// m_pTriggerButton->SetPos( posX, posY );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// position help label
|
||
|
CEconNotification *pNotification = g_notificationQueue.GetNotification( m_iNotificationID );
|
||
|
CExLabel *pHelpLabel = dynamic_cast< CExLabel* >( FindChildByName( "HelpTextLabel" ) );
|
||
|
if ( pHelpLabel )
|
||
|
{
|
||
|
if ( pNotification )
|
||
|
{
|
||
|
const wchar_t *pszText = NULL;
|
||
|
const char *pszTextKey = pNotification->GetUnlocalizedHelpText();
|
||
|
if ( pszTextKey )
|
||
|
{
|
||
|
pszText = g_pVGuiLocalize->Find( pszTextKey );
|
||
|
}
|
||
|
if ( pszText )
|
||
|
{
|
||
|
wchar_t wzFinal[512] = L"";
|
||
|
if ( ::input->IsSteamControllerActive() )
|
||
|
{
|
||
|
UTIL_ReplaceKeyBindings( pszText, 0, wzFinal, sizeof( wzFinal ), GAME_ACTION_SET_FPSCONTROLS );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UTIL_ReplaceKeyBindings( pszText, 0, wzFinal, sizeof( wzFinal ) );
|
||
|
}
|
||
|
ColorizeText( pNotification, pHelpLabel, wzFinal );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pHelpLabel->InvalidateLayout( true, false );
|
||
|
int posX, posY;
|
||
|
pHelpLabel->GetPos( posX, posY );
|
||
|
int iContentWidth, iContentHeight;
|
||
|
pHelpLabel->GetContentSize( iContentWidth, iContentHeight );
|
||
|
int iLabelWidth, iLabelHeight;
|
||
|
pHelpLabel->GetSize( iLabelWidth, iLabelHeight );
|
||
|
int iTextInsetX, iTextInsetY;
|
||
|
pHelpLabel->GetTextInset( &iTextInsetX, &iTextInsetY );
|
||
|
pHelpLabel->SetSize( iLabelWidth, iContentHeight + iTextInsetY );
|
||
|
posY = iHeight;
|
||
|
pHelpLabel->SetPos( posX, posY - iTextInsetY );
|
||
|
iHeight += iContentHeight + iTextInsetY;
|
||
|
}
|
||
|
|
||
|
// resize ourselves to fit the child height wise
|
||
|
int iContainerHeight = MAX( m_iOriginalHeight, iHeight );
|
||
|
SetSize( m_iOriginalWidth, m_iOverrideHeight != 0 ? m_iOverrideHeight : iContainerHeight );
|
||
|
}
|
||
|
|
||
|
virtual void OnCommand( const char *command )
|
||
|
{
|
||
|
CEconNotification *pNotification = g_notificationQueue.GetNotification( m_iNotificationID );
|
||
|
|
||
|
if ( pNotification != NULL )
|
||
|
{
|
||
|
if ( !Q_strncmp( command, "delete", ARRAYSIZE( "delete" ) ) )
|
||
|
{
|
||
|
pNotification->Deleted();
|
||
|
g_notificationQueue.RemoveNotification( m_iNotificationID );
|
||
|
return;
|
||
|
}
|
||
|
else if ( !Q_strncmp( command, "trigger", ARRAYSIZE( "trigger" ) ) )
|
||
|
{
|
||
|
pNotification->Trigger();
|
||
|
}
|
||
|
else if ( !Q_strncmp( command, "accept", ARRAYSIZE( "accept" ) ) )
|
||
|
{
|
||
|
pNotification->Accept();
|
||
|
}
|
||
|
else if ( !Q_strncmp( command, "decline", ARRAYSIZE( "decline" ) ) )
|
||
|
{
|
||
|
pNotification->Decline();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
BaseClass::OnCommand( command );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
BaseClass::OnCommand( command );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int GetOverrideHeight() const
|
||
|
{
|
||
|
return m_iOverrideHeight;
|
||
|
}
|
||
|
|
||
|
void SetOverrideHeight( int iHeight )
|
||
|
{
|
||
|
m_iOverrideHeight = iHeight;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
vgui::EditablePanel* m_pChild;
|
||
|
vgui::Panel* m_pTriggerButton;
|
||
|
vgui::Panel* m_pAcceptButton;
|
||
|
vgui::Panel* m_pDeclineButton;
|
||
|
int m_iNotificationID;
|
||
|
int m_iOriginalWidth;
|
||
|
int m_iOriginalHeight;
|
||
|
int m_iButtonOffsetY;
|
||
|
int m_iOverrideHeight;
|
||
|
bool m_bAddControls;
|
||
|
};
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
struct NotificationUIInfo_t
|
||
|
{
|
||
|
CNotificationToastControl *m_pPanel;
|
||
|
int m_iStartPosX;
|
||
|
int m_iStartPosY;
|
||
|
};
|
||
|
|
||
|
// notification queue panel that is a HUD element
|
||
|
// this is the visualization of the notifications while in game
|
||
|
class CNotificationQueuePanel : public CHudElement, public vgui::EditablePanel
|
||
|
{
|
||
|
DECLARE_CLASS_SIMPLE( CNotificationQueuePanel, vgui::EditablePanel );
|
||
|
public:
|
||
|
CNotificationQueuePanel( const char *pElementName )
|
||
|
: CHudElement( pElementName )
|
||
|
, BaseClass( NULL, "NotificationQueuePanel" )
|
||
|
, m_mapNotificationPanels( DefLessFunc(int) )
|
||
|
, m_flInvalidateTime( 0.0f )
|
||
|
, m_bInvalidated( false )
|
||
|
{
|
||
|
vgui::Panel *pParent = g_pClientMode->GetViewport();
|
||
|
SetParent( pParent );
|
||
|
|
||
|
SetHiddenBits( HIDEHUD_MISCSTATUS );
|
||
|
}
|
||
|
|
||
|
virtual ~CNotificationQueuePanel()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
virtual bool ShouldDraw( void )
|
||
|
{
|
||
|
if ( !CHudElement::ShouldDraw() )
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ( engine->IsPlayingDemo() )
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ( cl_notifications_show_ingame.GetInt() == 0 )
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
CHudVote *pHudVote = GET_HUDELEMENT( CHudVote );
|
||
|
if ( pHudVote && pHudVote->IsVoteUIActive() )
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return m_mapNotificationPanels.Count() > 0 || g_notificationQueue.HasItems();
|
||
|
}
|
||
|
|
||
|
virtual void PerformLayout( void )
|
||
|
{
|
||
|
BaseClass::PerformLayout();
|
||
|
|
||
|
// Get filtered list of only the notifications that show some in-game content
|
||
|
CUtlVector< CEconNotification *> notifications;
|
||
|
GetNotifications( notifications );
|
||
|
|
||
|
const float flMoveTime = cl_notifications_move_time.GetFloat();
|
||
|
float lerpPercentage = flMoveTime > 0 ? clamp( ( flMoveTime - m_flInvalidateTime ) / flMoveTime, 0.0f, 1.0f ) : 1.0f;
|
||
|
float flCurrTime = engine->Time();
|
||
|
|
||
|
// move the notifications around
|
||
|
const int kMaxVisibleNotifications = cl_notifications_max_num_visible.GetInt();
|
||
|
|
||
|
int iPosY = MIN( notifications.Count() - 1, kMaxVisibleNotifications - 1 ) * m_iOverlapOffset_Y;
|
||
|
int iPosX = MIN( notifications.Count() - 1, kMaxVisibleNotifications - 1 ) * m_iOverlapOffset_X;
|
||
|
int zpos = 100;
|
||
|
int iPreviousHeight = 0;
|
||
|
for ( int i = 0; i < notifications.Count(); ++i )
|
||
|
{
|
||
|
CEconNotification *pNotification = notifications[i];
|
||
|
int mapIdx = m_mapNotificationPanels.Find( pNotification->GetID() );
|
||
|
if ( m_mapNotificationPanels.IsValidIndex( mapIdx ) == false || pNotification->GetInGameLifeTime() < flCurrTime )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
NotificationUIInfo_t &info = m_mapNotificationPanels[mapIdx];
|
||
|
CNotificationToastControl *pPanel = info.m_pPanel;
|
||
|
if ( pPanel )
|
||
|
{
|
||
|
if ( pPanel->IsVisible() == false )
|
||
|
{
|
||
|
pPanel->SetVisible( true );
|
||
|
}
|
||
|
if ( i == 0 && pPanel->GetOverrideHeight() != 0 )
|
||
|
{
|
||
|
pPanel->SetOverrideHeight( 0 );
|
||
|
pPanel->InvalidateLayout( true, false );
|
||
|
}
|
||
|
int iPanelX;
|
||
|
int iPanelY;
|
||
|
pPanel->GetPos( iPanelX, iPanelY );
|
||
|
if ( m_bInvalidated )
|
||
|
{
|
||
|
info.m_iStartPosX = iPanelX;
|
||
|
info.m_iStartPosY = iPanelY;
|
||
|
}
|
||
|
int iNewPosX = iPosX;
|
||
|
int iNewPosY = iPosY;
|
||
|
iNewPosX = Lerp( lerpPercentage, info.m_iStartPosX, iNewPosX );
|
||
|
iNewPosY = Lerp( lerpPercentage, info.m_iStartPosY, iNewPosY );
|
||
|
pPanel->SetPos( iNewPosX, iNewPosY );
|
||
|
pPanel->SetZPos( --zpos );
|
||
|
bool bStoppedMoving = iNewPosX == iPanelX && iNewPosY == iPosY;
|
||
|
// only show panels that are more than we want visible if they are moving
|
||
|
if ( i > kMaxVisibleNotifications - 1 )
|
||
|
{
|
||
|
if ( bStoppedMoving )
|
||
|
{
|
||
|
pPanel->SetVisible( false );
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
// don't poke out underneath if we are visible and stopped moving
|
||
|
if ( i != 0 && pPanel->GetOverrideHeight() == 0 && bStoppedMoving )
|
||
|
{
|
||
|
pPanel->SetOverrideHeight( MIN( pPanel->GetTall(), iPreviousHeight ) );
|
||
|
pPanel->InvalidateLayout( true, false );
|
||
|
}
|
||
|
iPreviousHeight = pPanel->GetTall();
|
||
|
|
||
|
iPosY = MAX( 0, iPosY - m_iOverlapOffset_Y );
|
||
|
iPosX = MAX( 0, iPosX - m_iOverlapOffset_X );
|
||
|
}
|
||
|
}
|
||
|
m_bInvalidated = false;
|
||
|
SetTall( ScreenHeight() - m_iOriginalY );
|
||
|
}
|
||
|
|
||
|
virtual void ApplySchemeSettings( vgui::IScheme *scheme )
|
||
|
{
|
||
|
LoadControlSettings( "Resource/UI/Econ/NotificationQueuePanel.res" );
|
||
|
GetBounds( m_iOriginalX, m_iOriginalY, m_iOriginalWidth, m_iOriginalHeight );
|
||
|
|
||
|
BaseClass::ApplySchemeSettings( scheme );
|
||
|
}
|
||
|
|
||
|
virtual void OnThink()
|
||
|
{
|
||
|
BaseClass::OnThink();
|
||
|
|
||
|
if ( IsVisible() == false )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Get filtered list of only the notifications that show some in-game content
|
||
|
CUtlVector< CEconNotification *> notifications;
|
||
|
GetNotifications( notifications );
|
||
|
|
||
|
float flCurrTime = engine->Time();
|
||
|
|
||
|
// check to see if we have a panel for each notification
|
||
|
int i = 0;
|
||
|
for ( i = 0; i < notifications.Count(); ++i )
|
||
|
{
|
||
|
CEconNotification *pNotification = notifications[i];
|
||
|
int mapIdx = m_mapNotificationPanels.Find( pNotification->GetID() );
|
||
|
if ( m_mapNotificationPanels.IsValidIndex( mapIdx ) == false || pNotification->GetInGameLifeTime() < flCurrTime )
|
||
|
{
|
||
|
m_bInvalidated = true;
|
||
|
// create the panel and add it to the UI
|
||
|
// have it slide from the bottom
|
||
|
CNotificationToastControl *pControl = NULL;
|
||
|
int iPosX = 0, iPosY = 0;
|
||
|
vgui::EditablePanel *pPanel = pNotification->CreateUIElement( false );
|
||
|
if ( pPanel )
|
||
|
{
|
||
|
pControl = new CNotificationToastControl( this, pPanel, pNotification->GetID(), false );
|
||
|
pControl->GetPos( iPosX, iPosY );
|
||
|
pControl->SetPos( iPosX, ScreenHeight() );
|
||
|
iPosY = ScreenHeight();
|
||
|
}
|
||
|
NotificationUIInfo_t info = { pControl, iPosX, iPosY };
|
||
|
m_mapNotificationPanels.Insert( pNotification->GetID(), info );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// now check to see if we have panels and there is no matching notification
|
||
|
i = m_mapNotificationPanels.FirstInorder();
|
||
|
while ( m_mapNotificationPanels.IsValidIndex( i ) )
|
||
|
{
|
||
|
int idx = i;
|
||
|
i = m_mapNotificationPanels.NextInorder( i );
|
||
|
int iID = m_mapNotificationPanels.Key( idx );
|
||
|
|
||
|
CEconNotification *pNotification = g_notificationQueue.GetNotification( iID );
|
||
|
if ( pNotification == NULL || pNotification->GetInGameLifeTime() < flCurrTime )
|
||
|
{
|
||
|
// fade here, cause we don't really want to re-layout
|
||
|
NotificationUIInfo_t &info = m_mapNotificationPanels[idx];
|
||
|
vgui::EditablePanel *pPanel = info.m_pPanel;
|
||
|
if ( pPanel )
|
||
|
{
|
||
|
pPanel->MarkForDeletion();
|
||
|
}
|
||
|
m_mapNotificationPanels.RemoveAt( idx );
|
||
|
m_bInvalidated = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( m_bInvalidated )
|
||
|
{
|
||
|
m_flInvalidateTime = MAX( cl_notifications_move_time.GetFloat(), 0.0f );
|
||
|
}
|
||
|
if ( m_flInvalidateTime > 0 )
|
||
|
{
|
||
|
m_flInvalidateTime -= gpGlobals->frametime;
|
||
|
InvalidateLayout( true, false );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
typedef CUtlMap< int, NotificationUIInfo_t > tNotificationPanels;
|
||
|
tNotificationPanels m_mapNotificationPanels;
|
||
|
int m_iOriginalX;
|
||
|
int m_iOriginalY;
|
||
|
int m_iOriginalWidth;
|
||
|
int m_iOriginalHeight;
|
||
|
float m_flInvalidateTime;
|
||
|
bool m_bInvalidated;
|
||
|
|
||
|
CPanelAnimationVar( int, m_iVisibleBuffer, "buffer_between_visible", "5" );
|
||
|
CPanelAnimationVar( int, m_iOverlapOffset_X, "overlap_offset_x", "10" );
|
||
|
CPanelAnimationVar( int, m_iOverlapOffset_Y, "overlap_offset_y", "10" );
|
||
|
|
||
|
void GetNotifications(CUtlVector< CEconNotification *> ¬ifications )
|
||
|
{
|
||
|
const CUtlVector< CEconNotification *> &allNotifications = g_notificationQueue.GetItems();
|
||
|
|
||
|
for (int i = 0 ; i < allNotifications.Count() ; ++i )
|
||
|
{
|
||
|
CEconNotification *pNotification = allNotifications[i];
|
||
|
if ( pNotification->BShowInGameElements() )
|
||
|
{
|
||
|
notifications.AddToTail( pNotification );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
DECLARE_HUDELEMENT( CNotificationQueuePanel );
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
CEconNotification::CEconNotification()
|
||
|
: m_pText("")
|
||
|
, m_pSoundFilename( NULL )
|
||
|
, m_flExpireTime( engine->Time() + 10.0f )
|
||
|
, m_pKeyValues( NULL )
|
||
|
, m_bInUse( false )
|
||
|
, m_steamID()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
CEconNotification::~CEconNotification()
|
||
|
{
|
||
|
if ( m_pKeyValues )
|
||
|
{
|
||
|
m_pKeyValues->deleteThis();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CEconNotification::SetText( const char *pText )
|
||
|
{
|
||
|
m_pText = pText;
|
||
|
}
|
||
|
|
||
|
void CEconNotification::AddStringToken( const char* pToken, const wchar_t* pValue )
|
||
|
{
|
||
|
if ( m_pKeyValues == NULL )
|
||
|
{
|
||
|
m_pKeyValues = new KeyValues( "CEconNotification" );
|
||
|
}
|
||
|
m_pKeyValues->SetWString( pToken, pValue );
|
||
|
}
|
||
|
|
||
|
void CEconNotification::SetKeyValues( KeyValues *pKeyValues )
|
||
|
{
|
||
|
if ( m_pKeyValues != NULL )
|
||
|
{
|
||
|
m_pKeyValues->deleteThis();
|
||
|
}
|
||
|
m_pKeyValues = pKeyValues->MakeCopy();
|
||
|
}
|
||
|
|
||
|
KeyValues *CEconNotification::GetKeyValues() const
|
||
|
{
|
||
|
return m_pKeyValues;
|
||
|
}
|
||
|
|
||
|
const wchar_t *CEconNotification::GetText()
|
||
|
{
|
||
|
g_pVGuiLocalize->ConstructString_safe( m_wszBuffer, m_pText, m_pKeyValues );
|
||
|
return m_wszBuffer;
|
||
|
}
|
||
|
|
||
|
int CEconNotification::GetID() const
|
||
|
{
|
||
|
return m_iID;
|
||
|
}
|
||
|
|
||
|
void CEconNotification::SetLifetime( float flSeconds )
|
||
|
{
|
||
|
m_flExpireTime = engine->Time() + flSeconds;
|
||
|
}
|
||
|
|
||
|
float CEconNotification::GetExpireTime() const
|
||
|
{
|
||
|
return m_flExpireTime;
|
||
|
}
|
||
|
|
||
|
float CEconNotification::GetInGameLifeTime() const
|
||
|
{
|
||
|
return m_flExpireTime; // default's to passed in time unless otherwise set (for derived classes)
|
||
|
}
|
||
|
|
||
|
void CEconNotification::SetIsInUse( bool bInUse)
|
||
|
{
|
||
|
m_bInUse = bInUse;
|
||
|
}
|
||
|
|
||
|
bool CEconNotification::GetIsInUse() const
|
||
|
{
|
||
|
return m_bInUse;
|
||
|
}
|
||
|
|
||
|
void CEconNotification::SetSteamID( const CSteamID &steamID )
|
||
|
{
|
||
|
m_steamID = steamID;
|
||
|
}
|
||
|
|
||
|
const CSteamID &CEconNotification::GetSteamID() const
|
||
|
{
|
||
|
return m_steamID;
|
||
|
}
|
||
|
|
||
|
void CEconNotification::MarkForDeletion()
|
||
|
{
|
||
|
// to be deleted ASAP
|
||
|
m_flExpireTime = 0.0f;
|
||
|
}
|
||
|
|
||
|
CEconNotification::EType CEconNotification::NotificationType()
|
||
|
{
|
||
|
return eType_Basic;
|
||
|
}
|
||
|
|
||
|
bool CEconNotification::BHighPriority()
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void CEconNotification::Trigger()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void CEconNotification::Accept()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void CEconNotification::Decline()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void CEconNotification::Deleted()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void CEconNotification::Expired()
|
||
|
{
|
||
|
}
|
||
|
vgui::EditablePanel *CEconNotification::CreateUIElement( bool bMainMenu ) const
|
||
|
{
|
||
|
CGenericNotificationToast *pToast = new CGenericNotificationToast( NULL, m_iID, bMainMenu );
|
||
|
return pToast;
|
||
|
}
|
||
|
|
||
|
const char *CEconNotification::GetUnlocalizedHelpText()
|
||
|
{
|
||
|
switch ( NotificationType() )
|
||
|
{
|
||
|
case eType_AcceptDecline:
|
||
|
return "#Notification_AcceptOrDecline_Help";
|
||
|
case eType_MustTrigger:
|
||
|
case eType_Trigger:
|
||
|
return "#Notification_CanTrigger_Help";
|
||
|
default:
|
||
|
Assert( !"Unhandled enum value" );
|
||
|
// ---v
|
||
|
case eType_Basic:
|
||
|
return "#Notification_Remove_Help";
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
class CMainMenuNotificationsControl : public vgui::EditablePanel
|
||
|
{
|
||
|
DECLARE_CLASS_SIMPLE( CMainMenuNotificationsControl, vgui::EditablePanel );
|
||
|
public:
|
||
|
CMainMenuNotificationsControl( vgui::EditablePanel *pParent, const char *pElementName )
|
||
|
: BaseClass( pParent, pElementName )
|
||
|
, m_mapNotificationPanels( DefLessFunc(int) )
|
||
|
, m_iNumItems( 0 )
|
||
|
{
|
||
|
vgui::ivgui()->AddTickSignal( GetVPanel(), 250 );
|
||
|
}
|
||
|
|
||
|
virtual ~CMainMenuNotificationsControl()
|
||
|
{
|
||
|
vgui::ivgui()->RemoveTickSignal( GetVPanel() );
|
||
|
}
|
||
|
|
||
|
virtual void PerformLayout( void )
|
||
|
{
|
||
|
BaseClass::PerformLayout();
|
||
|
|
||
|
const CUtlVector< CEconNotification *> ¬ifications = g_notificationQueue.GetItems();
|
||
|
|
||
|
// position the notifications around
|
||
|
// grow down
|
||
|
int iTotalHeight = 0;
|
||
|
const int kBuffer = 5;
|
||
|
for ( int i = 0; i < notifications.Count(); ++i )
|
||
|
{
|
||
|
CEconNotification *pNotification = notifications[i];
|
||
|
int mapIdx = m_mapNotificationPanels.Find( pNotification->GetID() );
|
||
|
if ( m_mapNotificationPanels.IsValidIndex( mapIdx ) == false )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
NotificationUIInfo_t &info = m_mapNotificationPanels[mapIdx];
|
||
|
vgui::EditablePanel *pPanel = info.m_pPanel;
|
||
|
if ( pPanel )
|
||
|
{
|
||
|
int iPanelX;
|
||
|
int iPanelY;
|
||
|
int iWidth;
|
||
|
int iHeight;
|
||
|
pPanel->GetBounds( iPanelX, iPanelY, iWidth, iHeight );
|
||
|
int iNewPosX = iPanelX;
|
||
|
int iNewPosY = iTotalHeight;
|
||
|
pPanel->SetPos( iNewPosX, iNewPosY );
|
||
|
iTotalHeight += iHeight + kBuffer;
|
||
|
}
|
||
|
}
|
||
|
int iWidth, iHeight;
|
||
|
GetSize( iWidth, iHeight );
|
||
|
SetSize( iWidth, iTotalHeight );
|
||
|
if ( iTotalHeight != iHeight )
|
||
|
{
|
||
|
GetParent()->InvalidateLayout( false, false );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
virtual void OnTick()
|
||
|
{
|
||
|
if ( m_iNumItems != g_notificationQueue.GetItems().Count() )
|
||
|
{
|
||
|
m_iNumItems = g_notificationQueue.GetItems().Count();
|
||
|
PostActionSignal( new KeyValues("Command", "command", "notifications_update" ) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
virtual void OnThink()
|
||
|
{
|
||
|
BaseClass::OnThink();
|
||
|
|
||
|
if ( IsVisible() == false )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const CUtlVector< CEconNotification *> ¬ifications = g_notificationQueue.GetItems();
|
||
|
bool bInvalidated = false;
|
||
|
|
||
|
// check to see if we have a panel for each notification
|
||
|
int i = 0;
|
||
|
for ( i = 0; i < notifications.Count(); ++i )
|
||
|
{
|
||
|
CEconNotification *pNotification = notifications[i];
|
||
|
int mapIdx = m_mapNotificationPanels.Find( pNotification->GetID() );
|
||
|
if ( m_mapNotificationPanels.IsValidIndex( mapIdx ) == false )
|
||
|
{
|
||
|
bInvalidated = true;
|
||
|
CNotificationToastControl *pControl = NULL;
|
||
|
vgui::EditablePanel *pPanel = pNotification->CreateUIElement( true );
|
||
|
if ( pPanel )
|
||
|
{
|
||
|
pControl = new CNotificationToastControl( this, pPanel, pNotification->GetID(), true );
|
||
|
}
|
||
|
NotificationUIInfo_t info = { pControl, 0, 0 };
|
||
|
m_mapNotificationPanels.Insert( pNotification->GetID(), info );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// now check to see if we have panels and there is no matching notification
|
||
|
i = m_mapNotificationPanels.FirstInorder();
|
||
|
while ( m_mapNotificationPanels.IsValidIndex( i ) )
|
||
|
{
|
||
|
int idx = i;
|
||
|
i = m_mapNotificationPanels.NextInorder( i );
|
||
|
int iID = m_mapNotificationPanels.Key( idx );
|
||
|
if ( g_notificationQueue.GetNotification( iID ) == NULL )
|
||
|
{
|
||
|
NotificationUIInfo_t &info = m_mapNotificationPanels[idx];
|
||
|
vgui::EditablePanel *pPanel = info.m_pPanel;
|
||
|
if ( pPanel )
|
||
|
{
|
||
|
pPanel->MarkForDeletion();
|
||
|
}
|
||
|
m_mapNotificationPanels.RemoveAt( idx );
|
||
|
bInvalidated = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( bInvalidated )
|
||
|
{
|
||
|
InvalidateLayout( true, false );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
typedef CUtlMap< int, NotificationUIInfo_t > tNotificationPanels;
|
||
|
tNotificationPanels m_mapNotificationPanels;
|
||
|
int m_iNumItems;
|
||
|
};
|
||
|
|
||
|
// Show in UI
|
||
|
class CNotificationsPresentPanel : public vgui::EditablePanel
|
||
|
{
|
||
|
DECLARE_CLASS_SIMPLE( CNotificationsPresentPanel, vgui::EditablePanel );
|
||
|
public:
|
||
|
CNotificationsPresentPanel( vgui::Panel *pParent, const char* pElementName ) : vgui::EditablePanel( pParent, "NotificationsPresentPanel" )
|
||
|
{
|
||
|
SetMouseInputEnabled( true );
|
||
|
}
|
||
|
|
||
|
virtual ~CNotificationsPresentPanel()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
virtual void ApplySchemeSettings( vgui::IScheme *pScheme )
|
||
|
{
|
||
|
BaseClass::ApplySchemeSettings( pScheme );
|
||
|
|
||
|
LoadControlSettings( "Resource/UI/Econ/NotificationsPresentPanel.res" );
|
||
|
|
||
|
for ( int i = 0; i < GetChildCount(); i++ )
|
||
|
{
|
||
|
vgui::Panel *pChild = GetChild( i );
|
||
|
pChild->SetMouseInputEnabled( false );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
virtual void OnMousePressed(vgui::MouseCode code)
|
||
|
{
|
||
|
if ( code != MOUSE_LEFT )
|
||
|
return;
|
||
|
|
||
|
PostActionSignal( new KeyValues("Close") );
|
||
|
|
||
|
// audible feedback
|
||
|
const char *soundFilename = "ui/buttonclick.wav";
|
||
|
|
||
|
vgui::surface()->PlaySound( soundFilename );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
DECLARE_BUILD_FACTORY( CNotificationsPresentPanel );
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// External interface for the notification queue
|
||
|
|
||
|
int NotificationQueue_Add( CEconNotification *pNotification )
|
||
|
{
|
||
|
if ( !engine->IsInGame() || (cl_notifications_show_ingame.GetBool() && pNotification->BShowInGameElements()) )
|
||
|
{
|
||
|
vgui::surface()->PlaySound( pNotification->GetSoundFilename() );
|
||
|
}
|
||
|
return g_notificationQueue.AddNotification( pNotification );
|
||
|
}
|
||
|
|
||
|
CEconNotification *NotificationQueue_Get( int iID )
|
||
|
{
|
||
|
return g_notificationQueue.GetNotification( iID );
|
||
|
}
|
||
|
|
||
|
CEconNotification *NotificationQueue_GetByIndex( int idx )
|
||
|
{
|
||
|
return g_notificationQueue.GetNotificationByIndex( idx );
|
||
|
}
|
||
|
|
||
|
void NotificationQueue_RemoveAll()
|
||
|
{
|
||
|
g_notificationQueue.RemoveAllNotifications();
|
||
|
}
|
||
|
|
||
|
void NotificationQueue_Remove( int iID )
|
||
|
{
|
||
|
g_notificationQueue.RemoveNotification( iID );
|
||
|
}
|
||
|
|
||
|
void NotificationQueue_Remove( CEconNotification *pNotification )
|
||
|
{
|
||
|
g_notificationQueue.RemoveNotification( pNotification );
|
||
|
}
|
||
|
|
||
|
void NotificationQueue_Remove( NotificationFilterFunc func )
|
||
|
{
|
||
|
g_notificationQueue.RemoveNotifications( func );
|
||
|
}
|
||
|
|
||
|
int NotificationQueue_Count( NotificationFilterFunc func )
|
||
|
{
|
||
|
return g_notificationQueue.CountNotifications( func );
|
||
|
}
|
||
|
|
||
|
void NotificationQueue_Visit( CEconNotificationVisitor &visitor )
|
||
|
{
|
||
|
g_notificationQueue.VisitNotifications( visitor );
|
||
|
}
|
||
|
|
||
|
void NotificationQueue_Update()
|
||
|
{
|
||
|
g_notificationQueue.Update();
|
||
|
}
|
||
|
|
||
|
int NotificationQueue_GetNumNotifications()
|
||
|
{
|
||
|
return g_notificationQueue.GetItems().Count();
|
||
|
}
|
||
|
|
||
|
vgui::EditablePanel* NotificationQueue_CreateMainMenuUIElement( vgui::EditablePanel *pParent, const char *pElementName )
|
||
|
{
|
||
|
CMainMenuNotificationsControl *pControl = new CMainMenuNotificationsControl( pParent, pElementName );
|
||
|
pControl->AddActionSignalTarget( pParent );
|
||
|
return pControl;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
CON_COMMAND( cl_trigger_first_notification, "Tries to accept/trigger the first notification" )
|
||
|
{
|
||
|
const CUtlVector< CEconNotification *> ¬ifications = g_notificationQueue.GetItems();
|
||
|
if ( notifications.Count() > 0 )
|
||
|
{
|
||
|
CEconNotification *pNotification = notifications[0];
|
||
|
switch ( pNotification->NotificationType() )
|
||
|
{
|
||
|
case CEconNotification::eType_AcceptDecline:
|
||
|
pNotification->Accept();
|
||
|
break;
|
||
|
case CEconNotification::eType_MustTrigger:
|
||
|
case CEconNotification::eType_Trigger:
|
||
|
pNotification->Trigger();
|
||
|
case CEconNotification::eType_Basic:
|
||
|
break;
|
||
|
default:
|
||
|
Assert( !"Unhandled enum value" );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CON_COMMAND( cl_decline_first_notification, "Tries to decline/remove the first notification" )
|
||
|
{
|
||
|
const CUtlVector< CEconNotification *> ¬ifications = g_notificationQueue.GetItems();
|
||
|
if ( notifications.Count() > 0 )
|
||
|
{
|
||
|
CEconNotification *pNotification = notifications[0];
|
||
|
switch ( pNotification->NotificationType() )
|
||
|
{
|
||
|
case CEconNotification::eType_AcceptDecline:
|
||
|
pNotification->Decline();
|
||
|
break;
|
||
|
case CEconNotification::eType_MustTrigger:
|
||
|
break; // YOU MUUUSSTTTTT
|
||
|
case CEconNotification::eType_Trigger:
|
||
|
case CEconNotification::eType_Basic:
|
||
|
pNotification->Deleted();
|
||
|
pNotification->MarkForDeletion();
|
||
|
break;
|
||
|
default:
|
||
|
Assert( !"Unhandled enum value" );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
#include "confirm_dialog.h"
|
||
|
|
||
|
class CTFTestNotification : public CEconNotification
|
||
|
{
|
||
|
public:
|
||
|
CTFTestNotification( const char* pText, EType eType )
|
||
|
: CEconNotification()
|
||
|
, m_pText( pText )
|
||
|
, m_eType( eType )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
virtual EType NotificationType() OVERRIDE { return m_eType; }
|
||
|
|
||
|
virtual void Trigger() OVERRIDE
|
||
|
{
|
||
|
ShowMessageBox( "", m_pText, "#GameUI_OK" );
|
||
|
MarkForDeletion();
|
||
|
}
|
||
|
virtual void Accept() OVERRIDE
|
||
|
{
|
||
|
ShowMessageBox( "Accept", m_pText, "#GameUI_OK" );
|
||
|
MarkForDeletion();
|
||
|
}
|
||
|
virtual void Decline() OVERRIDE
|
||
|
{
|
||
|
ShowMessageBox( "Decline", m_pText, "#GameUI_OK" );
|
||
|
MarkForDeletion();
|
||
|
}
|
||
|
private:
|
||
|
const char *m_pText;
|
||
|
EType m_eType;
|
||
|
};
|
||
|
|
||
|
CON_COMMAND( cl_add_notification, "Adds a notification" )
|
||
|
{
|
||
|
if ( args.ArgC() >= 2 )
|
||
|
{
|
||
|
CEconNotification::EType eType = CEconNotification::eType_Basic;
|
||
|
if ( args.ArgC() >= 5 )
|
||
|
{
|
||
|
eType = (CEconNotification::EType)atoi( args[4] );
|
||
|
}
|
||
|
|
||
|
CEconNotification *pNotification = new CTFTestNotification( args[1], eType );
|
||
|
|
||
|
pNotification->SetText( args[1] );
|
||
|
if ( args.ArgC() >= 3 )
|
||
|
{
|
||
|
int iLifetime = atoi( args[2] );
|
||
|
pNotification->SetLifetime( iLifetime );
|
||
|
}
|
||
|
if ( args.ArgC() >= 4 )
|
||
|
{
|
||
|
if ( steamapicontext && steamapicontext->SteamUser() )
|
||
|
{
|
||
|
pNotification->SetSteamID( steamapicontext->SteamUser()->GetSteamID() );
|
||
|
}
|
||
|
}
|
||
|
int id = NotificationQueue_Add( pNotification );
|
||
|
Msg( "Added notification %d\n", id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|